第16章練習問題4

  • 投稿日:
  • by
  • カテゴリ:

 GUIの基本として、ボタンをクリックした時の動作をコールバックで実装する方式を勉強。コールバック関数を登録する際のラムダ式は、まだ記述方法がよくわかっていない。真似をしている段階だ。
 練習問題4は、以下の通り。

 円、正方形、正三角形、六角形をそれぞれ作成するアイテムが含まれたメニューを作成する。座標を指定するための入力ボックスを(1つまたは2つ)作成し、メニューアイテムを押すことによって作成された図形をその座標に配置する。ドラッグ&ドロップはサポートしない。

 メニューを作って、それぞれのボタンから図形を描画する関数を呼べばいいだけだ、と思った。確かにその通りなのだが、それが結構やっかいであった。17.2.9の手法を借用した。
 さらに、円、正方形は、CircleおよびRectangleを使えばいいが、正三角形、六角形はライブラリにないので、Closed_polylineでinitializer_listを使えるようにした関数NClosed_polylineを作って、作成するようにした。とりあえず、動いたのが、下記のコードである。

#include "Simple_window.h"
#include "Graph.h"

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

private:
    const int size = 50; //Size of Shape
    Shape* p;
    In_box posx;
    In_box posy;
    void circle_pressed();
    void square_pressed();
    void triangle_pressed();
    void hexagon_pressed();
    void quit_pressed();
};

Draw_menu::Draw_menu(Point xy, int w, int h, const string& title)
    :Window{ xy, w, h, title },
    posx{ Point{x_max() - 310,0},50,20,"x:" },
    posy{ Point{x_max() - 210,0},50,20,"y:" },
    shape_menu{ Point{x_max() - 100,0},70,20,Menu::vertical,"shape" }
{
    attach(posx);
    attach(posy);
    shape_menu.attach(new Button{ Point{0,0},0,0,"circle",
        [](Address, Address pw) {reference_to<Draw_menu>(pw).circle_pressed(); } });
    shape_menu.attach(new Button{ Point{ 0,0 },0,0,"square",
        [](Address, Address pw) {reference_to<Draw_menu>(pw).square_pressed(); } });
    shape_menu.attach(new Button{ Point{ 0,0 },0,0,"triangle",
        [](Address, Address pw) {reference_to<Draw_menu>(pw).triangle_pressed(); } });
    shape_menu.attach(new Button{ Point{ 0,0 },0,0,"hexagon",
        [](Address, Address pw) {reference_to<Draw_menu>(pw).hexagon_pressed(); } });
    shape_menu.attach(new Button{ Point{ 0,0 },0,0,"quit",
        [](Address, Address pw) {reference_to<Draw_menu>(pw).quit_pressed(); } });
    attach(shape_menu);
}

void Draw_menu::circle_pressed() {
    int x = posx.get_int();
    int y = posy.get_int();

    p = new Circle{ Point{ x + size/2, y + size/2}, size/2 };
    attach(*p);
    redraw();

}

void Draw_menu::square_pressed() {
    int x = posx.get_int();
    int y = posy.get_int();

    p = new Graph_lib::Rectangle { Point{ x , y }, size, size };
    attach(*p);
    redraw();

}

struct NClosed_polyline :Closed_polyline {
    NClosed_polyline(initializer_list<Point> lst){
        for (auto p:lst) Shape::add(p); }   
};


void Draw_menu::triangle_pressed() {
    int x = posx.get_int();
    int y = posy.get_int();
    const int h = static_cast<int>(sqrt(2.0) / 2.0 * size);

    p = new NClosed_polyline{
        Point{x + size / 2, y + (size - h) / 2 },
        Point{x + size,     y + (size + h) / 2 },
        Point{x,            y + (size + h) / 2 }};

    attach(*p);
    redraw();
}

void Draw_menu::hexagon_pressed() {
    int x = posx.get_int();
    int y = posy.get_int();
    const int h = static_cast<int>(sqrt(3.0) / 2.0 * size);

    p = new NClosed_polyline{
        Point{x + size / 4,     y + (size - h) / 2 },
        Point{x + size * 3 / 4, y + (size - h) / 2 },
        Point{x + size,         y + size / 2 },
        Point{x + size * 3 / 4, y + (size + h) / 2 },
        Point{x + size / 4,     y + (size + h) / 2 },
        Point{x,                y + size / 2 } };

    attach(*p);
    redraw();
}

void Draw_menu::quit_pressed() {
    hide();
}


int main()
{
    using namespace Graph_lib;

    try {
        Draw_menu win{ Point{100,100}, 600, 400, "Draw Shape" };
        return gui_main();
    }

    catch (exception& e) {
        cerr << "exception: " << e.what() << endl;
        return 1;
    }

    catch (...) {
        cerr << "Some exception" << endl;
        return 2;
    }
}