CSCE 121 Chapter 16

From Notes
Jump to navigation Jump to search

« previous | Wednesday, October 20, 2010 | next »


More intuitive GUI

  • window with components
  • Titles / Text
  • Fields / Dialogs
  • Buttons
  • mouse

GUI is based on two techniques:

  • Object-oriented programming
  • Events (like mouse click)

How do we do this?

  • define custom window not Simple_window
  • define buttons and boxes
  • listen for actions
  • storing entered text
  • creating lines, etc.

Answer:

struct Lines_window : Window {
  Lines_window(Point xy, int width, int height, const string& title);
  Open_polyline lines;

  private:
    // buttons
    Button next_button;
    Button quit_button;

    // i/o boxes
    In_box next_x;
    In_box next_y;
    Out_box xy_out;
    
    void next();   // what to do when next_button is pushed
    void quit();   // what to do when quit_button is pushed

    static void cb_next(Address, Address window);  // callback for next_button
    static void cb_quit(Address, Address window);  // callback for quit_button
};

Lines_window::Lines_window(Point xy, int w, int h, const string& title) : Window(xy, w, h, title),
    next_button(Point(x_max()-150,0), 70, 20, "Next point", cb_next),  // note callback cb_next
    quit_button(Point(x_max()-70,0), 70, 20, "Quit", cb_quit),         // note callback cb_quit
    next_x(Point(x_max()-310,0), 50, 20, "next x:"),
    next_y(Point(x_max()-210,0), 50, 20, "next y:"),
    xy_out(Point(100,0), 100, 20, "current (x,y):")
{
  attach(next_button);
  attach(quit_button);
  attach(next_x);
  attach(next_y);
  attach(xy_out);
  attach(lines);
}

All of the elements on the window are Widgets or "controls"

Callbacks

Connecting functions to widgets is messy in most GUIs:

  • System doesn't "know about" C++
  • callback maps system conventions to C++:
void Lines_window::cb_quit(Address, Address pw) {
  // First argument is not used, second argument is the current window
  // Call Lines_window::quit() for the window located at address pw
  reference_to<Lines_window>(pw).quit(); // map address into reference to type of object at that address (explained later)
}

void Lines_window::quit() {
  hide();
}

void Lines_window::next() {
  int x = next_x.get_int();
  int y = next_y.get_int();

  lines.add(Point(x,y));

  // update current position box:
  stringstream ss;
  ss << '(' << x << ',' << y << ')';
  xy_out.put(ss.str());

  redraw();  // redraw the screen
}

Summary

We know about:

  • Windows
  • Buttons
  • Textual Input/Output boxes
  • Graphical output

We still don't know about:

  • mouse tracking
  • menus
  • etc


Fancier Example

Lines_window.h

#include "Graph.h"
#include "GUI.h"
#include "Window.h"
#include <iostream>
#include <sstream>

struct Lines_window : Window {
  Lines_window(Point xy, int w, int h, const string& title);

  private:
    Open_polyline lines;
    Button next_button;
    Button quit_button;
    In_box next_x;
    In_box next_y;
    Out_box xy_out;
    Menu color_menu;
    Button menu_button;

    void change(Color c) {
      lines.set_color(c);
    }

    void hide_menu() {
      // hide color menu and show button to display menu
      color_menu.hide();
      menu_button.show();
    }


    // actions invoked by callbacks

    void menu_pressed() {
      // hide menu button and show color menu
      menu_button.hide();
      color_menu.show();
    }

    void red_pressed() {
      change(Color::red);
      hide_menu();
    }

    void blue_pressed() {
      change(Color::blue);
      hide_menu();
    }

    void black_pressed() {
      change(Color::black);
      hide_menu();
    }

    void next() { /* ... */ }
    void quit() { /* ... */ }


    // callbacks
    static void cb_red(Address, Address pw) {
      reference_to<Lines_window>(pw).red_pressed();
    }

    static void cb_blue(Address, Address pw) {
      reference_to<Lines_window>(pw).blue_pressed();
    }

    static void cb_black(Address, Address pw) {
      reference_to<Lines_window>(pw).black_pressed();
    }

    static void cb_next(Address, Address pw) {
      reference_to<Lines_window>(pw).next();
    }

    static void cb_quit(Address, Address pw) {
      reference_to<Lines_window>(pw).quit();
    }
};

Lines_window.cpp

#include "Lines_window.h"
Lines_window::Lines_window(Point xy, int w, int h, const string& title) : // initializer
  Window(xy, w, h, title),
  next_button(Point(x_max()-150, 0), 70, 20, "Next point", cb_next),
  quit_button(Point(x-max()-70, 0), 70, 20, "Quit", cb_quit),
  next_x(Point(x_max()-310, 0), 50, 20, "next x:"),
  next_y(Point(x_max()-210, 0), 50, 20, "next y:"),
  xy_out(Point(100, 0), 100, 20, "current (x,y):"),
  color_menu(Point(x_max()-70, 30), 70, 20, Menu::vertical, "color"),
  menu_button(Point(x_max()-70, 30), 70, 20, cb_menu)
{
  attach(next_button);
  attach(quit_button);
  attach(next_x);
  attach(next_y);

  attach(xy_out);
  xy_out.put("no point");

  color_menu.attach(new Button(Point(0,0), 0, 0, "red", cb_red));     // use 'new' to put button in heap; accessible after constructor is out of scope
  color_menu.attach(new Button(Point(0,0), 0, 0, "blue", cb_blue));
  color_menu.attach(new Button(Point(0,0), 0, 0, "black", cb_black));
  attach(color_menu);
  color_menu.hide();

  attach(menu_button);
  attach(lines);
}

void Lines_window::next() {
  int x = next_x.get_int();
  int y = next_y.get_int();
  lines.add(Point(x,y));
  stringstream ss;
  ss << '(' << x << ',' << y << ')';
  xy.put(ss.str());
  redraw();  // inherited from Window; refreshes the screen
}

main.cpp <syntaxhighlight lang="cpp">

  1. include "Lines_window.h"

using namespace Graph_lib; using namespace std; int main() {

 Lines_window(Point(100,100), 600, 400, "lines");
 return gui_main();  // inherited in Window