描画系

プログラムの紹介

まずは簡単なプログラムの紹介。

gui_draw.png

四角形を drag 操作で追加することができ(図の赤)、追加しおわった四角形群(図の青)とともに、順番に表示しています。

コンポーネントとしては、真ん中に Graph があり、あとボタンが付いているだけ。 今回は、クリック操作だけでなく、drag 操作を扱いたいので、enable_events=True, drag_submits=True と設定しています。

あと、Graph は、文字通りグラフとか書けるように、座標系を自分で指定できるようになっています。今回は、ほぼつかっていませんが、各種チャートを書きたいときは便利かもです。

    my_graph = sg.Graph((500, 500), (0, 0), (500, 500),
                        background_color='white',
                        enable_events=True, drag_submits=True,
                        key='graph')

MVC モデル

こういう描画系では、MVC モデルをつかうのが一般的です。

  • Model: 論理的なデータ構造
  • View: 論理データを GUI に表示したもの
  • Control: 論理データに操作するためのもの

モデルの例

まずは Model。今回は、追加済みの四角形や、 drag 中の四角形が対応します。こんな感じ。

    shapes = []  # 今までに配置した四角形を配置
    drag_begin = ()  # drag 中は、drag 始点を格納、それ以外は empty
    drag_current = ()  # drag 中は、drag 終点を格納、それ以外は empty

描画の例

View ですね。 Model に応じて描画をおこなうのですが、こんな感じ。 Graph には draw_rectangle など、図形を描画するためのメソッドが色々あるので、使ってください。 ポイントは、Event に応じて、毎回「差分」を書くんじゃなくて、最初に Erace() して、全部書き直しているところです。まあ、追記する感じでつくってもいいのかもしれませんが。

    def draw_canvas(self):
        self.my_graph.Erase()
        for left_top, right_bottom in self.shapes:
            self.my_graph.draw_rectangle(left_top, right_bottom, fill_color='blue', line_color='white')
        if self.drag_begin and self.drag_begin != self.drag_current:
            self.my_graph.draw_rectangle(self.drag_begin, self.drag_current, fill_color='red', line_color='white')

マウスイベントの処理

Control ですね。 マウスイベントは、普通は click されたときに、その位置座標をつかってなにかすればいいんだと思います。 drag の場合は、drag 開始時点と終了時点を判別するため、mouse のボタンダウン、アップを判別しないといけません。

以下のようにmouse 操作に応じて、Model に変更し、draw_canvas()すれば基本大丈夫なはず。

    def canvas_click(self, pos):  # drag 開始・drag 中の処理
        if not self.drag_begin:
            self.drag_begin = pos
        self.drag_current = pos
        print(self.drag_begin, self.drag_current)
        self.draw_canvas()

    def canvas_click_up(self, pos):  # drag 終点なら、図形として追加
        self.shapes.append((pos, self.drag_begin))
        self.drag_begin = self.drag_current = ()
        self.draw_canvas()