Graphics in Classes
Why Bother with Graphics and GUI?
Common Use: It is very common to use graphics in applications. If you are writing conventional PC applications, utilizing graphics is necessary.
Utility: Graphics provides instant feedback and is useful for graphing functions and displaying results. It can effectively illustrate useful concepts and techniques.
Language Features: Good graphics cannot be implemented without some advanced language features.
Teaching Importance: Key concepts can be non-trivial; hence, teaching graphics is valuable. Without guidance, new programmers might misinterpret graphics as "magic".
Enjoyment: Engaging with graphics can be fun for developers as well.
Graphics and GUI Overview
WYSIWYG: Stands for "What You See Is What You Get". This means there is a direct correspondence between the concepts in the code and what is displayed on the screen.
Display Model
Object Attachment: Objects such as graphs are “attached to” a window.
Display Engine: It invokes display commands (like drawing lines) for the objects present in the window.
Shape Class: The
Squareobject can contain vectors of lines, text, etc., which the window will draw.
Example: Display Model in Code
int main() {
using namespace Graph_lib; // use our graphics interface library
Point tl {100,200}; // a point (obviously)
Simple_window win {tl,600,400,"Canvas"}; // make a simple window
Polygon poly; // make a shape (a polygon, obviously)
poly.add(Point{300,200}); // add three points to the polygon
poly.add(Point{350,100});
poly.add(Point{400,200});
poly.set_color(Color::red); // make the polygon red (obviously)
win.attach(poly); // connect poly to the window
win.wait_for_button(); // give control to the display engine
}
Resulting Screen
Visualization of the described application window that displays the created polygon.
Graphics/GUI Libraries
Interface Classes: You will be using several interface classes developed for this course
GUI Toolkit: The course interfaces with a popular GUI toolkit - FLTK (Fast Light Tool Kit). Documentation can be found at www.fltk.org.
Installation: Instructions and support are available through specific labs (ex: Lab05).
Simplicity: This model is less complex compared to traditional toolkit interfaces which can span 370 pages. The custom interface library consists of roughly 20 classes and 500 lines of code.
Portability: The code is designed to work across Windows, Unix, Mac, etc.
Widespread Use: The principles from the course model can apply to most common graphics and GUI applications.
Graphics and GUI Architecture
Often referred to as layered architecture with distinct layers:
Operating System (e.g., Windows, Linux)
Interface Library
Graphical User Interface (e.g., FLTK)
Coordinates in Graphics
Y-Coordinate Growth: Notably, y-coordinates increase downwards (right, down) in the graphical display.
Window Resizing: The properties
x_max()andy_max()can be changed to resize the window and identify pixels on the screen.
Interface Class Structure
An arrow in programming languages often indicates that one class “is a kind of” another class.
Utility Classes: Classes like
Color,Line_style, andPointserve as utility classes and are utilized by other classes.Window Class: Acts as a bridge between the GUI library and the screen.
Code Organization
// Graphing interface: struct Shape { ... };
// Window interface: class Window { ... };
// FLTK headers
// Graph code
// Window code
main.cpp: Window.h: Window.cpp:
#include "Graph.h"
#include "Simple_window.h"
int main() { ... }
Graph.cpp: Graph.h: struct Point { ...}; ...
GUI code GUI.cpp: GUI.h: Point.h:
class Simple_window { ... }
Simple_window.h:
Source Files
Header Files: Contains interfaces and declarations.
Implementation Files: Code implementing interfaces and using headers. Examples include
Graph.handGraph.cpp.Caution should be observed when examining implementation files due to complex C++ features used therein.
Design Principles
Program Design Ideal: Aim to represent real-world concepts directly in code.
Example Representations:
Window: Represents a visual window on the screen that can differ across operating systems.
Simple_window: A window equipped with a "next button" for user interaction.
Line: Represents a line graphically depicted in the window.
Point: Defines coordinates in the graphic space.
Shape: Encapsulates common functionalities of graphical shapes.
The Color class should embody how colors are visually represented.
Object Structure in Graph_lib
namespace Graph_lib {
// our graphics interface is in Graph_lib
struct Point {
int x, y; // A Point is a pair of integers
};
bool operator==(Point a, Point b) {
return a.x == b.x && a.y == b.y;
}
bool operator!=(Point a, Point b) {
return !(a == b);
}
}
Line Class Implementation
Structure Definition: The
Shapeclass holds lines as pairs of points and knows how to display these lines. Line is a specific instance of Shape defined by two Points.
struct Line : Shape {
Line(Point p1, Point p2); // constructor declaration
};
Line::Line(Point p1, Point p2) {
add(p1); // adds the first point to this shape
add(p2);
}
Example: Drawing Lines
// draw two lines:
using namespace Graph_lib;
Simple_window win {Point{100,100}, 600, 400, "Canvas"}; // create a window
Line horizontal {Point{100,100}, Point{200,100}}; // horizontal line definition
Line vertical {Point{150,50}, Point{150,150}}; // vertical line definition
win.attach(horizontal); // Adding lines to the window
win.attach(vertical);
win.wait_for_button(); // Display the window
Lines Class
Definition: A
Linesobject is a group of lines, allowing manipulation as a whole.Functionality:
The empty set of lines can be initialized using a list.
Methods to add lines and execute drawings are provided.
Terminology:
Lines “is derived from” the Shape class, inheriting properties and methods.
Implementation of Lines
Lines::Lines(std::initializer_list<pair<Point, Point>> lst) {
for (auto p : lst) {
add(p.first, p.second);
}
}
Drawing Functionality
void Lines::draw_lines() const { // This function draws all the lines associated with this object
for (int i = 1; i < number_of_points(); i += 2) {
fl_line(point(i-1).x, point(i-1).y, point(i).x, point(i).y);
}
}
// Note: fl_line is a basic line drawing function from FLTK
Programming Ideals
Strives to capture the domain concepts directly in code. Understandable code reflects a comprehensible application domain.
Examples of Objects
Each graphical object should represent tangible things:
Window: Represents what is seen on-screen.
Line and Point: Graphical primitives shown on the screen.
Shape: Represents all types of shapes in the Graph/GUI model.
Encapsulation: To protect the internal state by creating private data members and public methods to manipulate them.
Data Privacy and Encapsulation
Data Hiding: Enforce private data to prevent unintended alterations.
Benefits of Private Members:
Enables implementation changes post-release.
Hides the underlying library types from users.
Prevents exposing unnecessary complexity, enhancing usability.
Potential Functionality Checks
Access functions may incorporate validation.
Typical usage:
c.set_radius(12);to set properties, with internal checks implemented in future iterations.
Regular Interfaces
Creating Objects: Illustrated by creating graphical instances using specific points.
For example:
Line ln {Point{100,200}, Point{300,400}};
Mark m {Point{100,200}, 'x'}; // marks a point with 'x'
Circle c {Point{200,200}, 250}; // instance of Circle
Rectangle s1 {Point{100,200}, 200, 300};
Building Blocks: Libraries
Definition: A library is a collection of functions and classes designed to work collaboratively to build applications.
Good Libraries: Should model a specific domain aspect without trying to cover everything.
Class Hierarchy
Shape Class: A base class that standardizes the behavior and attributes of derived shape classes (e.g., Polygon, Line).
Definitions and behaviors of classes are encapsulated under an accessible interface.
class Shape { public: // ... };
class Rectangle : Shape {...};
Class Shape Functionality
Attributes: Ties graphics objects to the screen, storing color, style, and coordinating points.
Methods:
void draw() const;virtual void move(int dx, int dy);void set_color(Color col);Point point(int i) const;
Shape's Private Data and Access Methods
Shape keeps its points encapsulated and allows access through public methods.
protected:
void add(Point p); // to append points
private:
vector<Point> points; // internal representation
Implementation of Draw Operations
Central to
Shapeis its ability to render graphics to the display. Drawing relies heavily on methods and inherited implementations to define visualization per shape type.
Virtual Functionality in Classes
Definitions of virtual functions enable polymorphic behavior, allowing specific behaviors to be defined in derived classes while adhering to a unified interface.
Object Layout in Inheritance
A derived class ('Circle', for example) includes its own attributes in addition to those inherited from its base class ('Shape'). This amalgamation supports flexible object modeling.
Hierarchies enhance maintainability and usability.
Benefits of Inheritance
Interface Inheritance: A polymorphic reference can interact with derived objects functionally.
Implementation Inheritance: Shared functionalities in base classes promote efficiency and ease of change management across derived classes, reducing code duplication and enabling simple feature expansion.
Pure Virtual Functions
Used to enforce that derived classes implement certain functions, forming abstract interfaces.
Conclusion
This structured approach to classes, objects, and interfaces underpins successful GUI application development. Key concepts in object-oriented programming, such as inheritance, polymorphism, and encapsulation, create a deliberate foundation for building effective software solutions.