参考サイトサイト
wxPythonで画像表示とかドラッグ移動とか勉強中http://blawat2015.no-ip.com/~mieki256/diary/201506251.html
上サイトのファイルがすばらしかったので自分なりに分析して、わかりやすいよう解説してみました。(幾分コードが変えてあります)
エクスプローラーから画像ファイルドロップ、コードの概要
以下のようにそれに関係あるコードのみ書き出しました。①MyFrameクラスにてMyFrameにドロップされるよう設定
②wx.FileDropTargetを継承したMyFileDropTargetクラスを作成。そのなかにOnDropFiles関数
を作成しドロップした画像のフルパスを取得します。
③それを引数として、MyFrame内関数LoadImage(filepath)を呼び出します。
④LoadImage→UpdateDrawing→MyObjのDraw でドラッグした画像の表示
MyObjは画像の描画、座標の管理などをしています。
class MyFrame(wx.Frame):
def __init__(self, parent=None, title=""):
wx.Frame.__init__(self, parent=parent, title=title, size=(800, 600))
...........
...........
# マウスカーソルを動かした時に呼ばれるメソッドを割り当てる
self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
# ファイルドロップの対象をフレーム全体に
#MyFrameにドロップされるよう設定
self.droptarget = MyFileDropTarget(self)
self.SetDropTarget(self.droptarget)
"""D&Dされた画像をロードして描画"""
#たぶんドラッグが終わったときに実行
#だとしたら、マウスイベントのupでも実行できるのでは?
#できなかった。マウスイベントは引き数の数がきまっている
def LoadImage(self, filepath):
print "LoadImage"
x, y = 0, 0
#ファイルパスから直接ビットマップを作成している?
b = wx.Bitmap(filepath)
#画像のビットマップと座標を受け取っている
obj = MyObj(b, x, y)
self.objs.append(obj)
x += 32
y += 32
self.UpdateDrawing() # 描画更新
"""ドラッグアンドドロップ担当クラス"""
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, obj):
wx.FileDropTarget.__init__(self)
#MyFrameに以下の設定があるので、objにはMyFrameがはいる
#self.droptarget = MyFileDropTarget(self)
self.obj = obj
#ファイルをドロップされた場合に、そのファイルを引数にして
#MyFrameのLoadImageを呼び出しているだけ。
"""ファイルをドロップした時の処理"""
def OnDropFiles(self, x, y, filenames):
#実験したらわかるが以下のfor文をとおさないことには実際の
#パスが得られない
for filepath in filenames:
self.obj.LoadImage(filepath)
"""マウスドラッグで移動できるオブジェクト用のクラス"""
#その画像の描画、座標の管理などをしている
class MyObj():
def __init__(self, bmp, x=0, y=0):
self.bmp = bmp # bitmapを記録
self.pos = wx.Point(x, y) # 表示位置を記録、self.posはタプル
self.diff_pos = wx.Point(0, 0)
表示された画像をマウスで動かすコードの概要
①マウスの左ボタンが押されたら
OnMouseLeftDown→MyObjのSavePosDiff(pos)→diff_pos = 画像の座標-マウス座標 を記録。
②マウスカーソルが動いた時
ドラッグしてる画像の座標がマウス座標で更新されます。
③マウスの左ボタンが離されたら
OnMouseLeftUp→MyObjのpos = 今のマウスのpos + diff_pos が代入されます。
つまり移動後のマウスのposに、最初の画像とマウス座標の差を加味されたものが、MyObjの
画像のposに入ります。
さらに、UpdateDrawing→Draw→MyObjのDraw でドラッグした画像の表示されます。
全コード
E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\dc\drop_gazou_hyouzi5_simple.py# coding: UTF-8
#wxPythonで画像表示とかドラッグ移動とか勉強中
#http://blawat2015.no-ip.com/~mieki256/diary/201506251.html
"""
Lキーをおして画像ファイルダイヤログ(エクスプローラー)をひらく
エクスプローラーから画像をドロップしてMyFrame上に表示。
画像ファイルをドラッグアンドドロップして移動させてMyFrame上に表示。
"""
import wx
dn = 0
"""マウスドラッグで移動できるオブジェクト用のクラス"""
#そのオブジェクトの描画、座標の管理などをしている
# obj = MyObj(b, self.x_drop, self.y_drop)となっており、(bは画像)
#画像ごとに、MyObjで管理されている。
class MyObj():
def __init__(self, bmp, x=0, y=0):
self.bmp = bmp # bitmapを記録
self.pos = wx.Point(x, y) # 表示位置を記録、self.posはタプル
self.diff_pos = wx.Point(0, 0)
print "MyObj self.pos",self.pos
"""与えられた座標とアタリ判定して結果を返す"""
def HitTest(self, pnt):
#pntはマウスpos selfはオブジェクト
#で、オブジェクト内にマウスが入っていればTrue
rect = self.GetRect() # 画像大きさに合わせての矩形領域を取得
return rect.InsideXY(pnt.x, pnt.y) # 座標が矩形内に入ってるか調べる
"""矩形領域を返す"""
#ここでは矩形を設定してその中にマウスが入れば、画像の位置
#をかえているだけで、特別なことは何もしていない。
#ちょとなれないメソッドがでただけで....
def GetRect(self):
return wx.Rect(self.pos.x, self.pos.y,
self.bmp.GetWidth(), self.bmp.GetHeight())
"""マウス座標と自分の座標の相対値を記録。"""
def SavePosDiff(self, pnt):
"""
マウス座標と自分の座標の相対値を記録。
この情報がないと、画像をドラッグした時の表示位置がしっくりこない
"""
#自分:クリックしたオブジェクトのことか?
#self.drag_obj.SavePosDiff(pos) とあるのでyes
self.diff_pos.x = self.pos.x - pnt.x
self.diff_pos.y = self.pos.y - pnt.y
# #通常の?画像表示
# Bitmap = None
# image = wx.Image(bitmap_image) #bitmap_image:元画像ふぁいる
# Bitmap = image.ConvertToBitmap()
# buffer = wx.EmptyBitmap(680,480)
# dc = wx.BufferedDC(None, self.buffer)
# dc.DrawBitmap(Bitmap, x, y, True)
# #このファイルの画像表示
# self._buffer = wx.EmptyBitmap(*size)
# dc = wx.BufferedDC(None, self._buffer)
# b = wx.Bitmap(filepath) #ここが違う
# obj = MyObj(b, x, y)
# dc.DrawBitmap(self.bmp, r.x, r.y, True)
"""与えられたDCを使って画像を描画する"""
def Draw(self, dc, select_enable):
print "MyObj Draw"
if self.bmp.Ok():
r = self.GetRect() # 矩形領域を取得
# ペンを設定しないと何故か描画できない
# 私の環境ではok
#dc.SetPen(wx.Pen(wx.BLACK, 4))
# 画像を描画
dc.DrawBitmap(self.bmp, r.x, r.y, True)
#select_enableは画像のまわりに赤い枠を描くかどうかの
#フラッグ
if select_enable:
# 画像枠を描画
dc.SetBrush(wx.TRANSPARENT_BRUSH) # 透明塗り潰し
dc.SetPen(wx.Pen(wx.RED, 1)) # 赤い線を指定
# 矩形を描画
dc.DrawRectangle(r.x, r.y, r.width, r.height)
return True
else:
return False
"""ドラッグアンドドロップ担当クラス"""
class MyFileDropTarget(wx.FileDropTarget):
def __init__(self, obj):
wx.FileDropTarget.__init__(self)
#MyFrameに以下の設定があるので、objにはMyFrameがはいる
#self.droptarget = MyFileDropTarget(self)
self.obj = obj
#この関数どこからもよびだされていない。
#内部的によびだされいるのだろう
#ファイルをドロップされた場合に、そのファイルを引数にして
#MyFrameのLoadImageを呼び出しているだけ。
"""ファイルをドロップした時の処理"""
def OnDropFiles(self, x, y, filenames):
#実験したらわかるが以下のfor文をとおさないことには実際の
#パスが得られない
for filepath in filenames:
self.obj.LoadImage(filepath)
print "filenames",filenames
print "filepath",filepath
#実行結果
#filenames [u'E:\\MyBackups\\goolgedrive\\myprg_main\\python_my_prg\\wxpython\\dc\\gazou_drop\\ball.png']
#filepath E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\dc\gazou_drop\ball.png
"""ダブルバッファで表示するFrame"""
class MyFrame(wx.Frame):
def __init__(self, parent=None, title=""):
wx.Frame.__init__(self, parent=parent, title=title, size=(800, 600))
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp)
# マウスカーソルを動かした時に呼ばれるメソッドを割り当てる
self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDownEvent)
# 画像格納用リストを初期化
self.objs = []
# マウスドラッグ処理用の変数を確保
self.drag_obj = None
self.drag_start_pos = wx.Point(0, 0)
# 描画用バッファ初期化のために一度 OnSize() を呼ぶ
self.OnSize()
# ファイルドロップの対象をフレーム全体に
#MyFrameにドロップされるよう設定
self.droptarget = MyFileDropTarget(self)
self.SetDropTarget(self.droptarget)
self.x_drop = 0
self.y_drop = 0
"""D&Dされた画像をロードして描画"""
#たぶんドラッグが終わったときに実行
#だとしたら、マウスイベントのupでも実行できるのでは?
#できなかった。マウスイベントは引き数の数がきまっている
def LoadImage(self, filepath):
print "LoadImage"
#ファイルパスから直接ビットマップを作成している?
b = wx.Bitmap(filepath)
#画像のビットマップと座標を受け取っている
obj = MyObj(b, self.x_drop, self.y_drop)
self.objs.append(obj)
#ドロップした画像を少しづつずらして表示
self.x_drop += 32
self.y_drop += 32
self.UpdateDrawing() # 描画更新
"""ウインドウサイズが変更された時に呼ばれる処理"""
def OnSize(self, event=None):
# クライアントのウインドウサイズを取得
#ClientSize :クライアントサイズは、ウィジェットに属する
#任意の罫線の内側のウィジェットの領域を表し、EVT_PAINTイ
#ベントで描画可能な領域です。 ウィジェットに境界線がない
#場合、クライアントのサイズはそのサイズと同じです
size = self.ClientSize
# ウインドウサイズで、空の描画用バッファ(bitmap)を作成
#*size 可変長変数。
#タプルを関数に渡すときに * を付けると、タプルの各要素を
#関数の引数として展開されて渡される
self._buffer = wx.EmptyBitmap(*size)
print size # (792, 573)
self.UpdateDrawing() # 描画更新
"""描画更新"""
def UpdateDrawing(self):
print "UpdateDrawing"
dc = wx.BufferedDC(None, self._buffer)
self.Draw(dc) # 実際の描画処理
print "Refresh"
self.Refresh(eraseBackground=False)
"""実際の描画処理"""
def Draw(self, dc):
print "Draw"
dc.Clear() # デバイスコンテキストでクリア
dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128)))
dc.SetPen(wx.Pen("RED", 3))
#つまり 輪郭が赤中が黄緑色?になる
dc.DrawCircle(10, 10, 100)
#objsで今までドラッグした画像を保存しておいて
#ドラッグ完了すると、ドラッグ中の画像もふくめて
#描画している
for obj in self.objs:
#MyObjのDraw呼び出し
obj.Draw(dc, True) # オブジェクトを描画
#obj.Draw(dc, False) # オブジェクトを描画
# 画像を3つドラッグした場合の関数のかかわり
# 画像のドラッグの順序により最初の方の画像が
# 最後の方の画像に隠れて表示される
"""画面書き換え要求があった時に呼ばれる処理"""
def OnPaint(self, event=None):
dc = wx.BufferedPaintDC(self, self._buffer)
"""マウス座標と重なってるオブジェクトを返す"""
def FindObj(self, pnt):
result = None
for obj in self.objs:
#pntマウスの座標と重なっているobjがあればTrue
if obj.HitTest(pnt):
result = obj
return result
"""マウスの左ボタンが押された時の処理"""
def OnMouseLeftDown(self, event):
# マウス座標を取得
pos = event.GetPosition()
#dnの変数もなくていいような?
global dn
dn += 1
print "mouse down"
print dn, pos
#マウス座標と重なってるオブジェクトを取得
obj = self.FindObj(pos)
#objが空でないなら、何かobjがあったら
#isのほうが==より処理がはやい
if obj is not None:
#ドラッグ移動するオブジェクトを記憶
self.drag_obj = obj
#drag_start_posはつかわれていないような?
# ドラッグ開始時のマウス座標を記録
self.drag_start_pos = pos
#diff_pos = 画像の座標-マウス座標 を記録。
self.drag_obj.SavePosDiff(pos)
"""マウスの左ボタンが離された時の処理"""
def OnMouseLeftUp(self, event):
if self.drag_obj is not None:
pos = event.GetPosition()
#移動後のマウスのposに、最初の画像とマウス座標の差を加味する
#それをdrag_objつまりMyObjのposに代入する
#つまり画像のposがかわる。
#diff_pos.x = self.pos.x - pnt.x
self.drag_obj.pos.x = pos.x + self.drag_obj.diff_pos.x
self.drag_obj.pos.y = pos.y + self.drag_obj.diff_pos.y
print "mouse up"
print self.drag_obj.pos.x , self.drag_obj.pos.y
self.drag_obj = None
print "mouse up None"
#UpdateDrawing→Draw→MyObjのDraw でドラッグした画像の表示
self.UpdateDrawing()
"""マウスカーソルが動いた時の処理"""
def OnMouseMotion(self, event):
print "mouse motion"
if self.drag_obj is None:
# ドラッグしてるオブジェクトが無いなら処理しない
return
# ドラッグしてるオブジェクトの座標値をマウス座標で更新
pos = event.GetPosition()
self.drag_obj.pos.x = pos.x + self.drag_obj.diff_pos.x
self.drag_obj.pos.y = pos.y + self.drag_obj.diff_pos.y
self.UpdateDrawing() # 描画更新
#Lキーをおしてファイルダイヤログをひらく
def OnKeyDownEvent(self, event):
k = event.GetKeyCode()
print k
# キーLがおされた
if 76==k:
self.openDialog()
def openDialog(self):
dp = "E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\dc\gazou_drop"
#osのファイルダイヤログをよびだす
# 引数 dp 開くフォルダ "":デフォルトのファイル名
# *.png : pngファイルだけ表示
d = wx.FileDialog(self, "画像ファイル", dp,"","*.png")
d.ShowModal()
d.Destroy()
if __name__ == '__main__':
# メイン処理
app = wx.App(False)
frame = MyFrame(None, "DnD Image display use Double Buffer")
frame.Show()
app.MainLoop()
0 件のコメント:
コメントを投稿