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 Square object 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() and y_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, and Point serve 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.h and Graph.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 Shape class 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 Lines object 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 Shape is 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.