"The world was black and white then. [It] didn't turn color until sometime in the 1930s." - Calvin's dad
This chapter presents a display model (the output part of GUI), giving examples of use and fundamental notions such as screen coordinates, lines, and color. Line, Lines, Polygons, Axis, and Text are examples of Shapes. A Shape is an object in memory that we can display and manipulate on a screen. The next two chapters will explore these classes further, with Chapter 13 focusing on their implementation and Chapter 14 on design issues.
12.1 Why graphics?
12.2 A display model
12.3 A first example
12.4 Using a GUI library
12.5 Coordinates
12.6 Shapes
12.7 Using Shape primitives
12.7.1 Graphics headers and main
12.7.2 An almost blank window
12.7.3 Axis
12.7.4 Graphing a function
12.7.5 Polygons
12.7.6 Rectangles
12.7.7 Fill
12.7.8 Text
12.7.9 Images
12.7.10 And much more
12.8 Getting this to run
12.8.1 Source files
- Page 468
Why do we spend four chapters on graphics and one on GUIs (graphical user interfaces)? After all, this is a book about programming, not a graphics book. There is a huge number of interesting software topics that we don't discuss, and we can at best scratch the surface on the topic of graphics. So, "Why graphics?" Basically, graphics is a subject that allows us to explore several important areas of software design, programming, and programming language facilities:
* Graphics are useful. There is much more to programming that graphics and much more to software than code manipulated through a GUI. However, in many areas good graphics are either essential or very important. For example, we wouldn't dream of studying scientific computing, data analysis, or just about any quantitative subject without the ability to graph data. Chapter 15 gives simple (but general) facilities for graphing data.
* Graphics are fun. There are few areas of computing where the effect of a piece of code is as immediately obvious and - when finally free of bugs- as pleasing. We'd be tempted to play with graphics even if it wasn't useful!
* Graphics provide lots of interesting code to read. Part of learning to program is to read lots of code to get a feel for what good code is like. -- Chapter 13 will demonstrate how you can write graphics code after another couple of hours.
* Graphics are a fertile source of design examples. It is actually hard to design and implement a good graphics and GUI library. Graphics are a very rich source of concrete and practical examples of design decisions and design techniques. Some of the most useful techniques for designing classes, designing functions, separataing software into layers (of abstraction), and constructing libraries can be illustrated with a relatively small amount of graphics and GUI code.
* Graphics provide a good introduction to what is commonly called object-oriented programming and the language features that support it. Despite rumors to the contrary, object-oriented programming wasn't invented to be able to do graphics (see Chapter 22), but it was soon applied to that, and graphics provide some of the most accessible examples of object-oriented designs.
* Some of the key graphics concepts are nontrivial. So they are worth teaching, rather than leaving it to your own initiative (and patience) to seek out information. If we did not show how graphics and GUI were done, you might consider them "magic," thus violating one of the fundamental aims of this book.
- Page 470
12.2 A display model
The iostream library is oriented toward reading and writing streams of characters as they might appear in a list of numeric values or a book. The only direct supports for the notion of graphical position are the newline and tab characters. You can embed notions of color and two-dimensional positions, etc. in a one-dimensional stream of characters.
-- The point is that you can express layout notions in plain text, but the connection between the characters written and what appears on the screen is indirect, governed by a program that interprets those "markup" commands. Such techniques are fundamentally simple and immensely useful (just about everything you read has been produces using them), but they also have their limitations.
In this chapter and the next four, we present an alternative: a notion of graphics and of graphical user interfaces that is directly aimed at a computer screen. The fundamental concepts are inherently graphical (and two-dimensional, adapted to the rectangular area of a computer screen), such as coordinates, lines, rectangles, and circles. The aim from a programming point of view is a direct correspondence between the objects in memory and the images on the screen.
The basic model is as follows : we compose objects with basic objects provided by a graphics system, such as lines. We "attach" these graphics objects to a window object, representing our physical screen. A program that we can think of as the display itself, as "a display engine," as "our graphics library," as "the GUI library," or even (humorously) as "the small gnome writing on the back of the screen," then takes the objects we have attached to our window and draws them on the screen.
The "display engine" draws lines on the screen, places strings of text on the screen, colors areas of the screen, etc. For simplicity, we'll use the phrase "our GUI library" or even "the system" for the display engine even though our GUI library does much more than just drawing objects. In the same way that our code lets the GUI library do most of the work for us, the GUI library delegates much of its work to the operating system.
12.3 A first example
Our job is to define classes from which we can make objects that we want to see on the screen. For example, we might want to draw a graph as a series of connected lines. Here is a small program presenting a very simple version of that:
#include "Simple_window.h" // get access to our window library
#include "Graph.h" // get access to our graphics library facilities
int main()
{
using namespace Graph_lib; // our graphics facilities are in Graph_lib
Point tl{100,100}; // to become top left corner of window
Simple_window win {tl, 600, 400, "Canvas"}; // make a simple window
Polygon poly; // make a shape (a polygon)
poly.add(Point{300,200}); // add a point
poly.add(Point{350, 100}); // add a point
poly.add(Point{400,200}); // add a point
poly.set_color(Color::red); // adjust properties of poly
win.attach(poly); // connect poly to window
win.wait_for_button(); // give control to the display engine
}
- Page 473
We use a class representing a window in our Graph_lib interface library called Simple_window. The name of this particular Simple_window is win; that is, win is a variable of class Simple_window. The initializer list for win starts with the point to be used as the top left corner, tl, followed by 600 and 400. Those are the width and height, respectively, of the window, as displayed on the screen, measured in pixels.
- Page 474
To get a GUI system to display objects on the screen, you have to give control to "the system." Our wait_for_button() does that, and it also waits for you to "press" ("click") the "Next" button of our Simple_window before proceeding. This gives you a chance to look at the window before the program finishes and the window disappears. When you press the button, the program terminates, closing the window.
-- You'll notice that we "cheated" a bit. Where did that button labeled "Next" come from? We built it into our Simple_window class. In Chapter 16, we'll move from Simple_window to "plain" Window, which has no potentially spurious facilities built in, and show how we can write our own code to control interaction with a window.
For the next three chapters, we'll simply use that "Next" button to move from one "display" to the next when we want to display information in stages ("frame by frame").
- Page 475
12.4 Using a GUI library
In this book, we will not use the operating system's graphical and GUI (graphical user interface) facilities directly. Doing so would limit our porgrams to run on a single operating system and would also force us to deal directly with a lot of messy details. As with text I/O, we'll use a library to smooth over operating system differences, I/O device variations, etc. and to simplify our code. Unfortunately, C++ does not provide a standard GUI library the way it provides the standard stream I/O library, so we use one of those GUI libraries, and to save you from hitting the full complexity of a GUI library all at once, we use a set of simple interface classes that can be implemented in a couple of hundred lines of code for just about any GUI library.
The GUI toolkit that we are using (indirectly for now) is called FLTK (Fast Light Took KIt), pronounced "full tick") from www.fltk.org. Our code is portable wherever FLTK is used (Windows, Unix, Mac, Linux, etc.) Our interface classes can also be re-implemented using other toolkits, so code using them is potentially even more portable.
The programming model presented by our interface classes is far simpler that what common toolkits offer. For example, our complete graphics and GUI interface library is about 600 lines of C++ code, whereas the extremely terse FLTK documentation is 370 pages.-- The general ideas presented in Chapters 12-16 can be used with any popular GUI toolkit. We will of course explain how our interfaces classes map to FLTK so that you will (eventually) see how you can use that (and similiar toolkits) directly, if necessary.
We can illustrate the parts of our "graphics world" like this:
our code -> our interface library -> A graphics/GUI library (here FLTK) -> The operating system(e.g., Windows or Linux) -> Our screen
Our interface classes provide a simple and user-extensible basic notion of two-dimensional shapes with limited support for the use of color. To drive that, we present a simple notion of GUI based on "callback" functions triggererd by the use of user-defined buttons, etc. on the screen (Chapter 16).
- Page 478
12.6 Shapes
12.7 Using Shape primitives
In this section, we will walk you through some of the primitive facilities of our graphics library: Simple_window, Window, Shape, Text, Polygon, Line, Lines, Rectangle, Color, Line_style, Point, Axis. The aim is to give you a broad view of what you can do with those facilities, but not yet a detailed understanding of any of those classes. In the next chapters, we explore the design of each.
- Page 479
12.7.1 Graphics headers and main
First, we include the header files defining our interface to the graphics and GUI facilities. As you probably guessed, Window.h contains the facilities related to windows and Graph.h the facilities related to drawing shapes (including text) into windows.
As usual, main() contains the code we want to execute (directly or indirectly) and deals with exceptions.
For this main() to compile, we need to have exception defined. We get that if we include std_lib_facilities.h as usual, or we could start to deal directly with standard headers and include <stdexcept>.
- Page 480
12.7.2 An almost blank window
- Page 482
12.7.3 Axis
An almost blank window isn't very interesting, so we'd better add some information. What would we like to display? Just to remind you that graphics is not all fun and games, we will start with something serious and somewhat complicated: an axis.
#include "Simple_window.h"
#include "Graph.h"
#include "std_lib_facilities.h"
using namespace Graph_lib;
int main()
try
{
Point tl{ 100,100 };
Simple_window win{ tl, 600, 400, "Canvas" };
Axis xa{ Axis::x, Point{20,300}, 280, 10, "x axis" };
win.attach(xa);
win.set_label("Canvas #2");
win.wait_for_button();
}
catch (exception& e)
{
cerr << e.what() << '\n';
return 1;
}
catch (...)
{
}
#include "Simple_window.h"
#include "Graph.h"
#include "std_lib_facilities.h"
using namespace Graph_lib;
int main()
try
{
Point tl{ 100,100 };
Simple_window win{ tl, 600, 400, "Canvas" };
Axis xa{ Axis::x, Point{20,300}, 280, 10, "x axis" };
win.attach(xa);
win.set_label("Canvas #2");
win.wait_for_button();
Axis ya{ Axis::y, Point{ 20, 300 }, 280, 10, "y axis" };
ya.set_color(Color::cyan);
ya.label.set_color(Color::dark_red);
win.attach(ya);
win.set_label("Canvas #3");
win.wait_for_button();
}
catch (exception& e)
{
cerr << e.what() << '\n';
return 1;
}
catch (...)
{
}
- Page 484
12.7.4 Graphing a function
What next? We now have a window with axes, so it seems a good idea to graph a function. We make a shape representing a sine function and attach it.
#include "Simple_window.h"
#include "Graph.h"
#include "std_lib_facilities.h"
using namespace Graph_lib;
int main()
try
{
Point tl{ 100,100 };
Simple_window win{ tl, 600, 400, "Canvas" };
Axis xa{ Axis::x, Point{20,300}, 280, 10, "x axis" };
win.attach(xa);
win.set_label("Canvas #2");
win.wait_for_button();
Axis ya{ Axis::y, Point{ 20, 300 }, 280, 10, "y axis" };
ya.set_color(Color::cyan);
ya.label.set_color(Color::dark_red);
win.attach(ya);
win.set_label("Canvas #3");
win.wait_for_button();
Function sine{ sin, 0, 100, Point{20, 150}, 1000, 50, 50 }; // sine curve
// plot sin() in the range [0:100] with (0,0) at (20, 150)
// using 1000 points; scale x values * 50, scale y values * 50
win.attach(sine);
win.set_label("Canvas #4");
win.wait_for_button();
}
catch (exception& e)
{
cerr << e.what() << '\n';
return 1;
}
catch (...)
{
}
Here, the Function named sine will draw a sine curve using the standard library function sin() to generate values. We explain details about how to graph functions in 15.3. For now, just note that to graph a function we have to say where it starts (a Point) and for what set of input values we want to see it (a range), and we need to give some information about how to squeeze that information into our window (scaling):
Note how the curve simple stops when it hits the edge of the window. Points drawn outside our window rectangle are simply ignored by the GUI system and never seen.
12.7.5 Polygons
A graphed function is an example of data presentation. We'll see much more of that in Chapter 15. However, we can also draw different kinds of objects in a window: geometric shapes. We use geometric shapes for graphical illustrations, to indicate user interaction elements (such as buttons), and generally to make our presentations more interesting. A Polygon is characterized by a sequence ofpoints, which the Polygon class connects by line. The first line connects the first point to the second, the second line connects the second point to the third, and the last line connects the last point to the first:
sine.set_color(Color::blue); // we changed our mind about sine's color
Polygon poly; // a polygon; a Polygon is a kind of Shape
poly.add(Point{ 300, 200 }); // three points make a triangle
poly.add(Point{ 350, 100 });
poly.add(Point{ 400, 200 });
poly.set_color(Color::red);
win.attach(poly);
win.wait_for_button();
-- Again, we set a color, and finally, we set a style. The lines of a Polygon have a "style." By default that is solid, but we can also make those lines dashed, dotted, etc. as needed (see 13.5). We get
- Page 487
12.7.6 Rectangles
-- So, most higher-level graphics libraries deal better with rectangles than with other closed shapes. Consequently, we provide Rectangle as a class separate from the Polygon class. A Rectangle is characterized by its top left corner plus a width and height:
Rectangle r{ Point{200, 200}, 100, 50 }; // top left corner, width, height
win.attach(r);
win.set_label("Canvas #6");
win.wait_for_button();
- Page 488
Please note that making a polyline with four points in the right places is not enough to make a Rectangle. It is easy to make a Closed_polyline that looks like a Rectangle on the screen (you can even make an Open_polyline that look just like a Rectangle); for example:
Closed_polyline poly_rect;
poly_rect.add(Point{ 100,50 });
poly_rect.add(Point{ 200,50 });
poly_rect.add(Point{ 200,100 });
poly_rect.add(Point{ 100,100 });
win.attach(poly_rect);
In fact, the image on the screen of such a poly_rect is a rectangle. However, the poly_rect object in memory is not a Rectangle and it does not "know" anything about rectangles. The simplest way to prove that is to add another point:
poly_rect.add(Point{50,75});
No rectangle has five points:
- Page 489
It is important for our reasoning about our code that a Rectangle doesn't just happen to look like a rectangle on the screen; it maintains the fundamental guarantees of a rectangle (As we know them from geometry). We write code that depends on a Rectangle really being a rectangle on the screen and staying that whay.
12.7.7 Fill
We have been drawing out shapes as outlines. We can also "fill" a rectangle with color:
r.set_fill_color(Color::yellow);
poly.set_style(Line_style(Line_style::dash, 4));
poly_rect.set_style(Line_style(Line_style::dash, 2));
poly_rect.set_fill_color(Color::green);
We also decided that we didn't like the line style of our triangle (poly), so we set its line style to "fat (thickness four times normal) dashed." Similarly, we changed the style of poly_rect (now no longer looking like a rectangle):
If you look carefully at poly_rect, you'll see that the outline is printed on top of the fill.
It is possible to fill any closed shape (See 13.9). Rectangles are just special in how easy (and fast) they are to fill.
- Page 490
12.7.8 Text
Finally, no system for drawing is complete without a simple way of writing text - drawing each character as a set of lines just doesn't cut it. We label the window itself, and axes can have labels, but we can also place text anywhere using a Text object:
Text t{ Point{150,150}, "Hello, graphical world!" };
win.attach(t);
From the primitive graphics elements you see in this window, you can build displays of just about any complexity and subtlety. For now, just note a peculiarity of the code in this chapter: there are no loops, no selection statements, and all data was "hardwired" in. The output was just composed of primitives in the simplest possible way. Once we start composing these primitives using data and algorithms, things will start to get interesting.
We have seen how we can control the color of text : the label of an Axis (!2.7.3) is a simply a Text object. In addition, we can choose a font and set the size of the characters:
Text t{ Point{150,150}, "Hello, graphical world!" };
t.set_font(Font::times_bold);
t.set_font_size(20);
win.attach(t);
We enlarged the characters of the Text string Hello, graphical world! to point size 20 and chose the Times font in bold:
- Page 492
12.7.9 Images
We can also load images from files:
Image ii{ Point{100,50}, "test.jpg" };
win.attach(ii);
As it happens, the file called test.jpg is a phot of two planes breaking the sound barrier:
That photo is relatively large and we placed it right on top of our text and shapes. So, to clean up our window a bit, let us move it a bit out of the way:
ii.move(100, 200);
Note how the parts of the photo that didn't fit in the window are simply not represented. What would have appeared outside the window is "clipped" away.
- Page 494
12.7.10 And much more
And here, without further comment, is some more code:
Circle c{ Point{100, 200}, 50 };
Ellipse e{ Point{100, 200}, 75, 25 };
e.set_color(Color::dark_red);
Mark m{ Point{100, 200}, 'x' };
ostringstream oss;
oss << "screen size: " << x_max() << "*" << y_max()
<< "; window size: " << win.x_max() << "*" << win.y_max();
Text sizes(Point{ 100, 20 }, oss.str());
Image cal{ Point{225, 225}, "test2.gif" };
cal.set_mask(Point{ 40,40 }, 200, 150);
win.attach(c);
win.attach(m);
win.attach(e);
win.attach(sizes);
win.attach(cal);
Can you guess what this code does? Is it obvious?
- Page 495
The connection between the code and what appears on the screen is direct. If you don't yet see how that code caused that output, it soon will become clear. Note the way we used an ostringstream (11.4) to format the text object displaying sizes.
12.8 Getting this to run
-- In the following chapters, we'll see how those Shape classees are defined and show more ways of using them.
Getting this program to run requires more than the programs we have presented so far. In addition to our code in main(), we need to get the interface library code compiled and linked to our code, and finally, nothing will run unless the FLTK library (or whatever GUI system we use) is installed and correctly linked to ours.
One way of looking at the program is that it has four distinct parts:
- Our program code (main(), etc.)
- Our interface library (Window, Shape, Polygon, etc.)
- The FLTK library
- The C++ standard library
Indirectly, we also use the operating system. Leaving out the OS and the standard library, we can illustrate the organization of our graphics code like this.
- Page 496
12.8.1 Source files
Our graphics and GUI interfaces library consists of ust five header files and three code files:
- Headers:
- Point.h
- Window.h
- Simple_window.h
- Graph.h
- GUI.h
- Code files:
- Window.cpp
- Graph.cpp
- GUI.cpp
Until Chapter 16, you can ignore the GUI files.
Drill
1. Get an empty Simple_window with the size 600 by 400 and a label My window compiled, linked, and run. Note that you have to link the FLTK library as described in Appendix D; #include Graph.h and Simple_window.h in your code; and include Graph.cpp and Window.cpp in your project.
2. Now add the examples from12.7 one by one, testing between each added subsection example.
3. Go through and make one minor change (e.g., in color, in location, or in number of points) to each of the subsection examples.
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 600, 400, "Canvas" }; Axis xa{ Axis::x, Point{20,300}, 280, 10, "x axis" }; win.attach(xa); Axis ya{ Axis::y, Point{ 20, 300 }, 280, 10, "y axis" }; ya.set_color(Color::cyan); ya.label.set_color(Color::dark_red); win.attach(ya); Function sine{ sin, 0, 100, Point{20, 150}, 1000, 50, 50 }; // sine curve // plot sin() in the range [0:100] with (0,0) at (20, 150) // using 1000 points; scale x values * 50, scale y values * 50 win.attach(sine); sine.set_color(Color::blue); // we changed our mind about sine's color Polygon poly; // a polygon; a Polygon is a kind of Shape poly.add(Point{ 300, 200 }); // three points make a triangle poly.add(Point{ 350, 100 }); poly.add(Point{ 400, 200 }); poly.set_color(Color::red); win.attach(poly); Rectangle r{ Point{200, 200}, 100, 50 }; // top left corner, width, height win.attach(r); Closed_polyline poly_rect; poly_rect.add(Point{ 100,50 }); poly_rect.add(Point{ 200,50 }); poly_rect.add(Point{ 200,100 }); poly_rect.add(Point{ 100,100 }); poly_rect.add(Point{ 50,75 }); win.attach(poly_rect); r.set_fill_color(Color::yellow); poly.set_style(Line_style(Line_style::dash, 4)); poly_rect.set_style(Line_style(Line_style::dash, 2)); poly_rect.set_fill_color(Color::green); Text t{ Point{150,150}, "Hello, graphical world!" }; t.set_font(Font::times_bold); t.set_font_size(20); win.attach(t); Image ii{ Point{100,50}, "test.jpg" }; win.attach(ii); ii.move(100, 200); Circle c{ Point{100, 200}, 50 }; Ellipse e{ Point{100, 200}, 75, 25 }; e.set_color(Color::dark_red); Mark m{ Point{100, 200}, 'x' }; ostringstream oss; oss << "screen size: " << x_max() << "*" << y_max() << "; window size: " << win.x_max() << "*" << win.y_max(); Text sizes(Point{ 100, 20 }, oss.str()); Image cal{ Point{225, 225}, "test2.gif" }; cal.set_mask(Point{ 40,40 }, 200, 150); win.attach(c); win.attach(m); win.attach(e); win.attach(sizes); win.attach(cal); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
Exercises
We recommend that you use Simple_window for these exercises.
1. Draw a rectangle as a Rectangle and as a Polygon. Make the lines of the Polygon red and the lines of the Rectangle blue.
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 600, 400, "Canvas" }; Polygon poly; // a polygon; a Polygon is a kind of Shape poly.add(Point{ 300, 200 }); poly.add(Point{ 300, 100 }); poly.add(Point{ 400, 100 }); poly.add(Point{ 400, 200 }); poly.set_color(Color::red); win.attach(poly); Rectangle r{ Point{200, 200}, 100, 50 }; // top left corner, width, height r.set_color(Color::blue); win.attach(r); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
2. Draw a 100-by-30 Rectangle and place the text "Howdy!" inside it.
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 600, 400, "Canvas" }; Rectangle r{ Point{200, 200}, 100, 30 }; // top left corner, width, height r.set_color(Color::blue); win.attach(r); Text myText(Point(225, 220), "Howdy!"); win.attach(myText); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
3. Draw your initials 150 pixels high. Use a thick line. Draw each initial in a different color.
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 600, 400, "Canvas" }; Text L(Point(200, 200), "L"); L.set_font_size(150); L.set_color(Color::cyan); Text C(Point(280, 200), "C"); C.set_font_size(150); C.set_color(Color::black); Text H(Point(400, 200), "H"); H.set_font_size(150); H.set_color(Color::dark_green); win.attach(L); win.attach(C); win.attach(H); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
6. What happens when you draw a Shape that doesn't fit inside its window? What happens when you draw a Window that doesn't fit on your screen? Write two programs that illustrate these two phenomena.
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 18000, 180000, "Canvas" }; Rectangle r(Point(0, 0), 700, 500); r.set_fill_color(Color::dark_magenta); win.attach(r); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
When I draw a rectangle that doesn't fit inside its window, the application just draw the rectangle. So, I can't the full view of the rectangle.
When I try to open a Window that doesn't fit on my screen, The window pop up. Howver, when I tried to open the very wide and long window (18000, 180000), the size of the window was minimized automatically.
13. Find a way to add color to the lines from the previous exercise. Make some lines one color and other lines another color or other colors
#include "Simple_window.h" #include "Graph.h" #include "std_lib_facilities.h" using namespace Graph_lib; int main() try { Point tl{ 100,100 }; Simple_window win{ tl, 600, 400, "Canvas" }; Line a(Point(0,0), Point(100,100)); a.set_color(Color::red); win.attach(a); win.set_label("Canvas #12"); win.wait_for_button(); return 0; } catch (exception& e) { cerr << e.what() << '\n'; return 1; } catch (...) { }
Postscript
The ideal for program design is to have our concepts directly represented as entities in our program. So, we often represent ideas by classes, real-world entities by objects of classes, and actions and computations by functions. Graphics is a domain where this idea has an obvious application. We have concepts, such as circles and polygons, and we represent them in our program as class Circle and class Polygon. Where graphics is unusual is that when writing a graphics program, we also have the opportunity to see objects of those classes on the screen; that is, the state of our program is directly represented for us to observe - in most applications we are not that lucky. This direct correspondence between ideas, code, and output is what makes graphics programming so attractive. Please do remember, though, that graphics are just illustrations of the general idea of using classes to directly represent concepts in code. That idea is far more general and useful: just about anything we can think of can be represented in code as a class, an object of a class, or a set of classes.
댓글 없음:
댓글 쓰기