2016/10/09(日) [n年前の日記]
#3 [python] wxPythonを再勉強中
wxPythonで表示したウインドウの中でマウスを動かすと何かが描ける、ようなことをしてみたい。
◎ ウインドウ内がちらつく版。 :
最初に書いたのはコレ。
_drawing_test.py
しかしこのスクリプトは画面がちらつく。
_drawing_test.py
""" 描画テスト。 マウスボタンを押した時だけ画面に何かを描画する。 ただし、この書き方では画面がちらつく。 VerySimpleDrawing - wxPyWiki https://wiki.wxpython.org/VerySimpleDrawing wxPythonのPaintDCでアンチエイリアスや透過を使う :右京web http://hujimi.seesaa.net/article/161079355.html """ import wx bg_image = "images/bg.jpg" class DrawPanel(wx.Frame): def __init__(self, *args, **kwargs): """初期化""" wx.Frame.__init__(self, *args, **kwargs) # ワーク確保 self.mouseLeftFlag = False self.pos = wx.Point(0, 0) # イベント割り当て self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) self.Bind(wx.EVT_MOTION, self.OnMouseMove) # 背景bitmap画像読み込み image = wx.Image(bg_image) self.bitmap = image.ConvertToBitmap() # 画像サイズでフレームサイズを設定し直し self.SetSize(image.GetSize()) def OnMouseLeftDown(self, e): """ 左ボタンを押した時の処理 """ pos = e.GetPosition() self.pos = pos self.mouseLeftFlag = True self.Refresh() def OnMouseMove(self, e): """ マウスカーソルを動かした時の処理 """ if self.mouseLeftFlag: pos = e.GetPosition() self.pos = pos self.Refresh() def OnMouseLeftUp(self, e): """ 左ボタンを離した時の処理 """ pos = e.GetPosition() self.pos = pos self.mouseLeftFlag = False self.Refresh() def OnPaint(self, event=None): """ 描画処理 """ pdc = wx.PaintDC(self) try: # アンチエイリアスをかける dc = wx.GCDC(pdc) except: dc = pdc dc.Clear() dc.DrawBitmap(self.bitmap, 0, 0, True) # 背景ビットマップ画像を描画 if self.mouseLeftFlag: # 円を描画 dc.SetBrush(wx.Brush(wx.Colour(255, 0, 0, 64))) dc.SetPen(wx.Pen("RED", 2)) x = self.pos.x - 50 y = self.pos.y - 50 dc.DrawEllipse(x, y, 100, 100) if __name__ == '__main__': app = wx.App(False) frame = DrawPanel(parent=None, title=u"ウインドウ内でマウスボタンを押してみるべし") frame.Show() app.MainLoop()
しかしこのスクリプトは画面がちらつく。
◎ ウインドウ内がちらつかない版。 :
画面がちらつかないようにするには、wx.BufferedDC() を使うといいらしい。
_drawing_test2.py
たしかにちらつかなくなった。
_drawing_test2.py
""" 描画テスト。 マウスボタンを押した時だけ画面に何かを描画する。 ちらつきを少なくする。 VerySimpleDrawing - wxPyWiki https://wiki.wxpython.org/VerySimpleDrawing wxPythonのPaintDCでアンチエイリアスや透過を使う :右京web http://hujimi.seesaa.net/article/161079355.html wxPython の画面に色々描く(+マウスのイベントを処理する) - 見切り発車 http://d.hatena.ne.jp/uyamae/20090305/1236261541 """ import wx class DrawPanel(wx.Frame): def __init__(self, *args, **kwargs): """初期化""" wx.Frame.__init__(self, *args, **kwargs) # ワーク確保 self.mouseLeftFlag = False self.pos = wx.Point(0, 0) # イベント割り当て self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) self.Bind(wx.EVT_MOTION, self.OnMouseMove) # 画像読み込み image = wx.Image("images/bg.jpg") self.bitmap = image.ConvertToBitmap() # 画像サイズでフレームサイズを設定し直し self.SetSize(image.GetSize()) def OnMouseLeftDown(self, e): """ 左ボタンを押した時の処理 """ pos = e.GetPosition() self.pos = pos self.mouseLeftFlag = True self.Refresh(False) def OnMouseMove(self, e): """ マウスカーソルを動かした時の処理 """ if self.mouseLeftFlag: pos = e.GetPosition() self.pos = pos self.Refresh(False) def OnMouseLeftUp(self, e): """ 左ボタンを離した時の処理 """ pos = e.GetPosition() self.pos = pos self.mouseLeftFlag = False self.Refresh(False) def OnPaint(self, event=None): """ 描画処理 """ pdc = wx.BufferedDC(wx.PaintDC(self)) try: # アンチエイリアスをかける dc = wx.GCDC(pdc) except: dc = pdc dc.Clear() dc.DrawBitmap(self.bitmap, 0, 0, True) # ビットマップ画像を描画 if self.mouseLeftFlag: # 円を描画 dc.SetBrush(wx.Brush(wx.Colour(255, 0, 0, 64))) dc.SetPen(wx.Pen("RED", 2)) x = self.pos.x - 50 y = self.pos.y - 50 dc.DrawEllipse(x, y, 100, 100) if __name__ == '__main__': app = wx.App(False) frame = DrawPanel(parent=None, title=u"ウインドウ内でマウスボタンを押してみるべし") frame.Show() app.MainLoop()
たしかにちらつかなくなった。
◎ スクロールできる版。 :
調子に乗って、ウインドウ内をスクロールできるソレにしてみた。ついでにブラシ相当をビットマップ画像にして描画。
_drawing_test3.py
実験に使った画像は以下。スクリプトと同じ場所に images というフォルダを作成して、その中に入れて使った。
_bg.jpg
_ball.png
_drawing_test3.py
""" 画面にマウスで円を描画する。 スクロールバーでウインドウをスクロールできる版。 """ import wx draw_bitmap_brsuh = True bitmap_brush_image = "images/ball.png" class DrawPanel(wx.ScrolledWindow): def __init__(self, parent): wx.ScrolledWindow.__init__(self, parent, -1) self.maxWidth = 1024 self.maxHeight = 768 self.rate = wx.Point(8, 8) self.brushBitmap = None if draw_bitmap_brsuh: image = wx.Image(bitmap_brush_image) self.brushBitmap = image.ConvertToBitmap() self.SetVirtualSize((self.maxWidth, self.maxHeight)) self.SetScrollRate(self.rate.x, self.rate.y) # 空のビットマップを確保。以後はこれに描画していく self.buffer = wx.EmptyBitmap(self.maxWidth, self.maxHeight) self.buttonFlag = False self.DrawFirst() # 初期描画 # イベント割り当て self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftButtonEvent) self.Bind(wx.EVT_LEFT_UP, self.OnLeftButtonEvent) self.Bind(wx.EVT_MOTION, self.OnLeftButtonEvent) def OnPaint(self, event=None): dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA) def OnLeftButtonEvent(self, event): if self.IsAutoScrolling(): self.StopAutoScrolling() pos = event.GetPosition() if event.LeftDown(): # マウスの左ボタンを押した self.DrawMiniCircle(pos.x, pos.y) self.buttonFlag = True elif event.Dragging() and self.buttonFlag: # マウスカーソルを動かした if self.buttonFlag: self.DrawMiniCircle(pos.x, pos.y) elif event.LeftUp() and self.buttonFlag: # マウスの左ボタンを離した self.buttonFlag = False def DrawMiniCircle(self, x, y): """ 指定座標に小さい円を描画 """ pdc = wx.BufferedDC(None, self.buffer) try: # アンチエイリアスをかける dc = wx.GCDC(pdc) except: dc = pdc # スクロールを考慮した座標値を取得 nx, ny = self.CalcUnscrolledPosition(x, y) if draw_bitmap_brsuh: # ビットマップ画像をブラシにして描画 nx -= self.brushBitmap.GetWidth() / 2 ny -= self.brushBitmap.GetHeight() / 2 dc.DrawBitmap(self.brushBitmap, nx, ny, True) else: # 円をブラシにして描画 dc.SetBrush(wx.Brush(wx.Colour(192, 192, 255))) dc.SetPen(wx.Pen("BLACK", 0)) dc.DrawCircle(nx, ny, 16) del dc self.Refresh(False) def DrawFirst(self): """ 初期描画 """ pdc = wx.BufferedDC(None, self.buffer) try: dc = wx.GCDC(pdc) except: dc = pdc dc.SetBackground(wx.Brush(self.GetBackgroundColour())) dc.Clear() # 円を描画 dc.SetBrush(wx.Brush(wx.Colour(128, 128, 255))) dc.SetPen(wx.Pen("GREEN", 1)) dc.DrawCircle(100, 100, 100) dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128))) dc.SetPen(wx.Pen("RED", 3)) dc.DrawCircle(self.maxWidth - 100, 100, 100) del dc class MyApp(wx.App): def OnInit(self): frame = wx.Frame(None, -1, "Draw Test 3", size=(640, 480)) DrawPanel(frame) frame.Show() self.SetTopWindow(frame) return True if __name__ == '__main__': app = MyApp() app.MainLoop()
実験に使った画像は以下。スクリプトと同じ場所に images というフォルダを作成して、その中に入れて使った。
_bg.jpg
_ball.png
この記事へのツッコミ
[ ツッコミを読む(1) | ツッコむ ]
以上です。
wxPython始めたばかりなんですが、ubuntuのpython3.6.8でウインドウ内がちらつく版。でもちらつかないですね。