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でウインドウ内がちらつく版。でもちらつかないですね。