mieki256's diary



2016/10/09() [n年前の日記]

#3 [python] wxPythonを再勉強中

wxPythonで表示したウインドウの中でマウスを動かすと何かが描ける、ようなことをしてみたい。

ウインドウ内がちらつく版。 :

最初に書いたのはコレ。

_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()

しかしこのスクリプトは画面がちらつく。

wxpython_ss1.gif

ウインドウ内がちらつかない版。 :

画面がちらつかないようにするには、wx.BufferedDC() を使うといいらしい。

_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()

たしかにちらつかなくなった。

wxpython_ss2.gif

スクロールできる版。 :

調子に乗って、ウインドウ内をスクロールできるソレにしてみた。ついでにブラシ相当をビットマップ画像にして描画。

_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()

wxpython_ss3.gif


実験に使った画像は以下。スクリプトと同じ場所に images というフォルダを作成して、その中に入れて使った。

_bg.jpg
_ball.png

以上です。

過去ログ表示

Prev - 2016/10 - Next
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project