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アプリのウインドウ内に表示したくて、アレコレ試しているところだったりするのでした。
[ ツッコむ ]
以上です。
