2019/11/11(月) [n年前の日記]
#1 [wxpython][python] pycairoの描画結果をwxPythonで表示
PyGTK を使うと、入力欄を含んだ Widget を表示するだけで謎の警告メッセージが出てしまう。GTK+ は使えんなと。
ならば、他のGUIライブラリはどうだろう。試したら、少なくとも wxPython はその手のメッセージは出さなかったので、GUI部分は wxPython で書こうかなと。
しかし、pycairo で surface に描画した結果を、wxPython で表示することはできるのかな。どうなんだろう。
試してみた。一応できた。たぶん。環境は、Windows10 x64 + Python 2.7.17 32bit + wxPython 4.0.7.post1 + pycairo 1.8.10。
Generateボタンをクリックすると、pycairo を使って、surface 内に、ランダムに矩形を描画して、その surface を wxPython で表示する。みたいな。
_wxpython_with_pycairo.py
以下のページを参考にした。ありがたや。
_python - Drawing with cairo in wxpython - Stack Overflow
肝は、このあたりだろうか…。
それと、wxPython の Widget の再描画は、.Refresh() を呼べばいいらしい。どうすれば再描画してくれるのか分からなくて、ちょっとハマった。
ならば、他のGUIライブラリはどうだろう。試したら、少なくとも wxPython はその手のメッセージは出さなかったので、GUI部分は wxPython で書こうかなと。
しかし、pycairo で surface に描画した結果を、wxPython で表示することはできるのかな。どうなんだろう。
試してみた。一応できた。たぶん。環境は、Windows10 x64 + Python 2.7.17 32bit + wxPython 4.0.7.post1 + pycairo 1.8.10。
Generateボタンをクリックすると、pycairo を使って、surface 内に、ランダムに矩形を描画して、その surface を wxPython で表示する。みたいな。
_wxpython_with_pycairo.py
import wx import wx.lib.wxcairo import cairo import random import math import time random_seed = 42 def make_texture(tw, th): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, tw, th) cr = cairo.Context(surface) # fill BG cr.set_source_rgb(0, 0, 0) cr.rectangle(0, 0, tw, th) cr.fill() random.seed(random_seed) # fill rectangles for i in range(96): w = int(random.uniform(tw * 0.02, tw * 0.25)) h = int(random.uniform(th * 0.02, th * 0.25)) x = random.randint(0 - w, tw - 1) y = random.randint(0 - h, th - 1) r = random.uniform(0.0, 1.0) g = random.uniform(0.0, 1.0) b = random.uniform(0.0, 1.0) a = random.uniform(0.0, 1.0) cr.set_source_rgba(r, g, b, a) cr.rectangle(x, y, w, h) cr.fill() return surface class MyDrawingArea(wx.Panel): def __init__(self, parent): super(MyDrawingArea, self).__init__(parent, wx.ID_ANY, size=(512, 512)) self.w, self.h = 512, 512 self.SetBackgroundColour([64, 64, 64]) self.SetDoubleBuffered(True) self.Bind(wx.EVT_PAINT, self.on_paint) def on_paint(self, e): dc = wx.PaintDC(self) cr = wx.lib.wxcairo.ContextFromDC(dc) # w, h = self.Size.GetWidth(), self.Size.GetHeight() self.surface = make_texture(self.w, self.h) cr.set_source_surface(self.surface, 0, 0) cr.paint() class MyFrame(wx.Frame): def __init__(self, title): super(MyFrame, self).__init__(None, title=title, size=(720, 600)) self.panel = wx.Panel(self) self.btn1 = wx.Button(self.panel, wx.ID_ANY, "Generate") self.btn1.Bind(wx.EVT_BUTTON, self.on_click_generate) self.btn2 = wx.Button(self.panel, wx.ID_ANY, "Redraw") self.btn2.Bind(wx.EVT_BUTTON, self.on_click_redraw) self.darea = MyDrawingArea(self.panel) self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.btn1, 2) self.vbox.Add(self.btn2, 1) self.hbox = wx.BoxSizer(wx.HORIZONTAL) self.hbox.Add(self.darea, 4, wx.EXPAND | wx.ALL, 8) self.hbox.Add(self.vbox, 1) self.panel.SetSizer(self.hbox) def on_click_generate(self, event): global random_seed random_seed = math.floor(time.time() * 100) self.darea.Refresh() def on_click_redraw(self, event): self.darea.Refresh() def main(): app = wx.App(False) frm = MyFrame("wxPython with pycairo") frm.Show() app.MainLoop() if __name__ == '__main__': main()
以下のページを参考にした。ありがたや。
_python - Drawing with cairo in wxpython - Stack Overflow
肝は、このあたりだろうか…。
import wx import wx.lib.wxcairo # ... def on_paint(self, e): dc = wx.PaintDC(self) cr = wx.lib.wxcairo.ContextFromDC(dc) self.surface = make_texture(self.w, self.h) cr.set_source_surface(self.surface, 0, 0) cr.paint()
それと、wxPython の Widget の再描画は、.Refresh() を呼べばいいらしい。どうすれば再描画してくれるのか分からなくて、ちょっとハマった。
def on_click_redraw(self, event): self.darea.Refresh()
◎ 余談。 :
GUIアプリのウインドウ内で図形描画をするだけなら、wxPython にも図形描画機能があるので、全て wxPython の機能だけで実験ができるのだけど。
今回は、GIMP の Python-Fu (Gimp-Python) にも流用できる図形描画処理を書きたくて。となると、pycairo縛りで図形描画する必要があって。故に、pycairo の描画結果をGUIアプリのウインドウ内に表示したくて、アレコレ試しているところだったりするのでした。
今回は、GIMP の Python-Fu (Gimp-Python) にも流用できる図形描画処理を書きたくて。となると、pycairo縛りで図形描画する必要があって。故に、pycairo の描画結果をGUIアプリのウインドウ内に表示したくて、アレコレ試しているところだったりするのでした。
[ ツッコむ ]
以上です。