2019/11/04(月) [n年前の日記]
#2 [python][pycairo] pycairoについて勉強中
以下のサイトのサンプルコードを動かしながら勉強中。
_PyCairo backends
_Basic drawing in PyCairo
環境は、Windows10 x64 1903 + Python 2.7.17 + PyGTK 2.24.0 + pycairo 1.8.10。
 _PyCairo backends
_Basic drawing in PyCairo
環境は、Windows10 x64 1903 + Python 2.7.17 + PyGTK 2.24.0 + pycairo 1.8.10。
◎ PyGTK を使ってテスト。 :
gtk2を使って、pycairo の描画結果を表示してみる。元のサンプルは、以下のページにある。
_PyCairo backends
件のサンプルコードは Python 3.x + PyGObject 用だけど、自分の環境は、Python 2.7.x + PyGTK なので、記述を変えないといけない。
手元の環境で動くように変更した版。
_04_gtkwindow.py
結果表示。

_PyCairo backends
件のサンプルコードは Python 3.x + PyGObject 用だけど、自分の環境は、Python 2.7.x + PyGTK なので、記述を変えないといけない。
手元の環境で動くように変更した版。
_04_gtkwindow.py
# Python 2.7 + PyGTK
import pygtk
import gtk
import cairo
pygtk.require("2.0")
# Python 3.x + PyGObject
# import gi
# gi.require_version('Gtk', '3.0')
# from gi.repository import Gtk
class MyDrawingArea(gtk.DrawingArea):
    """My DrawingArea."""
    def __init__(self):
        super(MyDrawingArea, self).__init__()
        self.connect("size-allocate", self.on_self_size_allocate)
        self.connect("expose-event", self.on_self_expose_event)
    def on_self_size_allocate(self, widget, allocation):
        """Resize."""
        print("resize")
        self.__width = allocation.width
        self.__height = allocation.height
    def on_self_expose_event(self, widget, event):
        """Draw for pycairo."""
        print("draw")
        ctx = widget.window.cairo_create()
        ctx.set_source_rgb(0, 0, 0)
        ctx.select_font_face("Sans", cairo.FONT_SLANT_NORMAL,
                             cairo.FONT_WEIGHT_NORMAL)
        ctx.set_font_size(40)
        ctx.move_to(10, 50)
        ctx.show_text("Disziplin ist Macht.")
class MyApp(object):
    def __init__(self):
        self.window = gtk.Window()
        self.darea = MyDrawingArea()
        self.window.add(self.darea)
        self.window.connect("delete-event", self.on_delete_event)
        self.window.set_title("GTK window")
        self.window.resize(420, 140)
        # Python 2.7 + PyGTK
        self.window.set_position(gtk.WIN_POS_CENTER)
        # Python 3.7 + PyGObject
        # self.window.set_position(gtk.WindowPosition.CENTER)
    def on_delete_event(self, window, event, data=None):
        gtk.main_quit()
        return False
    def main(self):
        self.window.show_all()
        gtk.main()
if __name__ == "__main__":
    app = MyApp()
    app.main()
- import 関係を変更。
 - Gtk. は、gtk. に書き換え。
 - drawイベントは、expose-event に置き換えた。
 
結果表示。

◎ lineの表示。 :
 pycairo を使って line を描画してみる。元サンプルは以下。
_Basic drawing in PyCairo
手元の環境で動くように修正した版。
_05_lines.py
ウインドウ内で何ヶ所か左クリックしてから右クリックすると、クリックした位置を全て繋ぐ線が描かれる。
結果表示。
ちょっとハマったのは、マウスクリックイベントを取得するあたり。クリックしてもイベントが発生しなくておかしいなと思っていたら、以下の一行が抜けていた…。
この一行が無いと、マウスクリックを取得できない模様。
_python - Mouse event in DrawingArea with PyGtk - Stack Overflow
_Basic drawing in PyCairo
手元の環境で動くように修正した版。
_05_lines.py
# Python 2.7 + PyGTK
import pygtk
import gtk
import cairo
pygtk.require("2.0")
# Python 3.x + PyGObject
# import gi
# gi.require_version('Gtk', '3.0')
# from gi.repository import Gtk
class MouseButton:
    LEFT_BUTTON = 1
    RIGHT_BUTTON = 3
class MyDrawingArea(gtk.DrawingArea):
    """My DrawingArea."""
    def __init__(self):
        super(MyDrawingArea, self).__init__()
        self.connect("size-allocate", self.on_self_size_allocate)
        self.connect("expose-event", self.on_self_expose_event)
        self.set_events(gtk.gdk.BUTTON_PRESS_MASK)
        # self.connect("button_press_event", self.on_button_press)
        self.connect("button-press-event", self.on_button_press)
        self.coords = []
    def on_self_size_allocate(self, widget, allocation):
        print("resize")
        self.__width = allocation.width
        self.__height = allocation.height
    def on_button_press(self, w, e):
        if e.type == gtk.gdk.BUTTON_PRESS:
            if e.button == MouseButton.LEFT_BUTTON:
                print("LEFT BUTTON")
                self.coords.append([e.x, e.y])
            elif e.button == MouseButton.RIGHT_BUTTON:
                print("RIGHT BUTTON")
                self.queue_draw()
    def on_self_expose_event(self, widget, event=None):
        """Draw for cairo."""
        print("on_draw")
        c = widget.window.cairo_create()
        c.set_source_rgb(0, 0, 0)
        c.set_line_width(0.5)
        for i in self.coords:
            for j in self.coords:
                c.move_to(i[0], i[1])
                c.line_to(j[0], j[1])
                c.stroke()
        del self.coords[:]
class MyApp(gtk.Window):
    def __init__(self):
        super(MyApp, self).__init__()
        self.connect("destroy", gtk.main_quit)
        self.darea = MyDrawingArea()
        self.add(self.darea)
        self.set_title("Lines")
        # Python 2.7 + PyGTK
        self.set_size_request(512, 512)
        self.set_position(gtk.WIN_POS_CENTER)
        # Python 3.7 + PyGObject
        # self.resize(300, 200)
        # self.set_position(gtk.WindowPosition.CENTER)
        self.show_all()
if __name__ == "__main__":
    app = MyApp()
    gtk.main()
ウインドウ内で何ヶ所か左クリックしてから右クリックすると、クリックした位置を全て繋ぐ線が描かれる。
結果表示。
ちょっとハマったのは、マウスクリックイベントを取得するあたり。クリックしてもイベントが発生しなくておかしいなと思っていたら、以下の一行が抜けていた…。
self.set_events(gtk.gdk.BUTTON_PRESS_MASK)
この一行が無いと、マウスクリックを取得できない模様。
_python - Mouse event in DrawingArea with PyGtk - Stack Overflow
[   ツッコむ ]
以上です。
