2015/06/25(木) [n年前の日記]
#1 [python] wxPythonで画像表示とかドラッグ移動とか勉強中
Python + wxPython を使って、エクスプローラから画像ファイルをドラッグアンドドロップして読み込んで表示して、それらの画像をマウスでドラッグ移動、するところまではできた。
このくらいできれば、後は細かいアレコレを追加していけばレイアウトツールぐらいは作れそうかなと。
このくらいできれば、後は細かいアレコレを追加していけばレイアウトツールぐらいは作れそうかなと。
#! /usr/bin/env python
# -*- mode: python; Encoding: utf-8; coding: utf-8 -*-
"""
画像ファイルをドラッグアンドドロップしてダブルバッファで表示。
マウスドラッグで画像表示位置を移動してみるテスト
Windows7 x64 + Python 2.7.10 + wxPython 3.0.2.0 で動作確認。
"""
import wx
USE_BUFFERED_DC = True
class MyObj():
"""マウスドラッグで移動できるオブジェクト用のクラス"""
def __init__(self, bmp, x=0, y=0):
"""コンストラクタ"""
self.bmp = bmp # bitmapを記録
self.pos = wx.Point(x, y) # 表示位置を記録
self.diff_pos = wx.Point(0, 0)
def HitTest(self, pnt):
"""与えられた座標とアタリ判定して結果を返す"""
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.diff_pos.x = self.pos.x - pnt.x
self.diff_pos.y = self.pos.y - pnt.y
def Draw(self, dc, select_enable):
"""与えられたDCを使って画像を描画する"""
if self.bmp.Ok():
r = self.GetRect() # 矩形領域を取得
# ペンを設定しないと何故か描画できない
dc.SetPen(wx.Pen(wx.BLACK, 4))
dc.DrawBitmap(self.bmp, r.x, r.y, True) # 画像を描画
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)
self.obj = obj # ファイルのドロップ対象を覚えておく
def OnDropFiles(self, x, y, filenames):
"""ファイルをドロップした時の処理"""
self.obj.LoadImage(filenames) # 親?の画像読み込みメソッドを呼ぶ
class MyFrame(wx.Frame):
"""ダブルバッファで表示するFrame"""
def __init__(self, parent=None, title=""):
"""コンストラクタ"""
wx.Frame.__init__(self, parent=parent, title=title, size=(800, 600))
# PAINTイベント、SIZEイベントで呼ばれるメソッドを割り当てる
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.objs = []
# マウスドラッグ処理用の変数を確保
self.drag_obj = None
self.drag_start_pos = wx.Point(0, 0)
# 描画用バッファ初期化のために一度 OnSize() を呼ぶ
self.OnSize()
# ファイルドロップの対象をフレーム全体に
self.droptarget = MyFileDropTarget(self)
# ファイルドロップ受け入れを設定
self.SetDropTarget(self.droptarget)
def LoadImage(self, files):
"""D&Dされた画像をロードして描画"""
x, y = 0, 0
for filepath in files:
b = wx.Bitmap(filepath)
obj = MyObj(b, x, y)
self.objs.append(obj)
x += 32
y += 32
self.UpdateDrawing() # 描画更新
def OnSize(self, event=None):
"""ウインドウサイズが変更された時に呼ばれる処理"""
size = self.ClientSize # クライアントのウインドウサイズを取得
# ウインドウサイズで、空の描画用バッファ(bitmap)を作成
self._buffer = wx.EmptyBitmap(*size)
self.UpdateDrawing() # 描画更新
def UpdateDrawing(self):
"""描画更新"""
dc = wx.MemoryDC()
dc.SelectObject(self._buffer)
self.Draw(dc) # 実際の描画処理
del dc # Update()が呼ばれる前に MemoryDC を削除しておく必要がある
# Falseを指定して背景を消さなくしたら画面のちらつきが出なくなった
self.Refresh(eraseBackground=False)
self.Update()
def Draw(self, dc):
"""実際の描画処理"""
dc.Clear() # デバイスコンテキストでクリア
for obj in self.objs:
obj.Draw(dc, True) # オブジェクトを描画
def OnPaint(self, event=None):
"""画面書き換え要求があった時に呼ばれる処理"""
if USE_BUFFERED_DC:
# ダブルバッファを使う場合
dc = wx.BufferedPaintDC(self, self._buffer)
else:
# ダブルバッファを使わない場合
dc = wx.PaintDC(self)
dc.DrawBitmap(self._buffer, 0, 0, True)
def FindObj(self, pnt):
"""マウス座標と重なってるオブジェクトを返す"""
result = None
for obj in self.objs:
if obj.HitTest(pnt):
result = obj
return result
def OnMouseLeftDown(self, event):
"""マウスの左ボタンが押された時の処理"""
pos = event.GetPosition() # マウス座標を取得
obj = self.FindObj(pos) # マウス座標と重なってるオブジェクトを取得
if obj is not None:
self.drag_obj = obj # ドラッグ移動するオブジェクトを記憶
self.drag_start_pos = pos # ドラッグ開始時のマウス座標を記録
self.drag_obj.SavePosDiff(pos)
def OnMouseLeftUp(self, event):
"""マウスの左ボタンが離された時の処理"""
if self.drag_obj is not None:
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.drag_obj = None
self.UpdateDrawing()
def OnMouseMotion(self, event):
"""マウスカーソルが動いた時の処理"""
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() # 描画更新
if __name__ == '__main__':
# メイン処理
app = wx.App(False)
frame = MyFrame(None, "DnD Image display use Double Buffer")
frame.Show()
app.MainLoop()
[ ツッコむ ]
#2 [prog] Atomエディタを再インストール
Pythonスクリプトを書く際に、Atomエディタを試用していたのだけど。(環境は Windows7 x64。)
日付挿入ができる _date というパッケージをインストールしたら、Atomエディタがエラーを出すようになってしまって。 _Package.getActivationCommands is deprecated. - Issue #3 - dannyfritz/atom-date によると、Atom現行版では問題が起きるから使わないでくれ、と書いてあるように見える。残念。
しかし、アンインストールしようとしても、Atomエディタ上からはアンインストールできず。いや、おそらくアンインストールはできてるのだろうけど、ファイル → 環境設定 → install の画面で、インストール済みっぽい表示が消えてくれない状態になってしまって。
apm というコマンドラインツールを使えば、コマンドラインからパッケージのインストール・アンインストールができるらしいので、
仕方ないから、Atomをアンインストールして、再インストールしてみたり。
日付挿入ができる _date というパッケージをインストールしたら、Atomエディタがエラーを出すようになってしまって。 _Package.getActivationCommands is deprecated. - Issue #3 - dannyfritz/atom-date によると、Atom現行版では問題が起きるから使わないでくれ、と書いてあるように見える。残念。
しかし、アンインストールしようとしても、Atomエディタ上からはアンインストールできず。いや、おそらくアンインストールはできてるのだろうけど、ファイル → 環境設定 → install の画面で、インストール済みっぽい表示が消えてくれない状態になってしまって。
apm というコマンドラインツールを使えば、コマンドラインからパッケージのインストール・アンインストールができるらしいので、
apm uninstall date apm install date等を繰り返してみたのだけど変化無し。
仕方ないから、Atomをアンインストールして、再インストールしてみたり。
◎ インストールしたパッケージ。 :
再インストール後にインストールしたパッケージは以下。apm list で表示できる。
C:\Users\USERNAME\.atom\packages (17) ├── atom-beautify@0.28.5 ├── autocomplete-paths@1.0.2 ├── autocomplete-python@0.5.0 ├── autocomplete-ruby@0.1.0 ├── color-picker@2.0.7 ├── emmet@2.3.10 ├── file-icons@1.5.8 ├── highlight-line@0.11.0 ├── highlight-selected@0.10.1 ├── japan-util@0.1.1 ├── japanese-menu@0.7.0 ├── japanese-wrap@0.2.10 ├── japanese-zen-han-convert@0.4.0 ├── minimap@4.10.0 ├── open-recent@2.2.4 ├── project-manager@1.15.10 └── script@2.25.2
◎ コメント行の見た目を変更。 :
コメント行がイタリック表示になってるのが気に入らないので、Themes → your stylesheet で辿り着ける styles.less に以下を追加して変更。
atom-text-editor::shadow .comment {
font-style: normal;
}
◎ キー割り当てを変更。 :
Keybindings → your keymap file で辿り着ける keymaps.cson に以下を追加。
'atom-text-editor:not([mini])': 'ctrl-,': 'unset!' '.platform-win32 atom-text-editor, .platform-linux atom-text-editor': 'ctrl-shift-B': 'unset!' 'shift-F5': 'script:close-view' 'F5': 'script:run' 'atom-text-editor': 'alt-f': 'native!' 'atom-workspace atom-text-editor': 'ctrl-k ctrl-k': 'editor:delete-to-end-of-line' # 'atom-text-editor': # 'alt-shift-D': 'date:datetime'
- emmet が Ctrl + , を使ってしまって、設定画面を開く Ctrl + , が使えなくなったので、emmet 側の割り当てを無効に。
- script(現在開いてるファイルを実行)を、F5 と Shift + F5に割り当て。
- Windows標準の Alt + F でファイルメニューが開くショートカットが使えないので修正。
- Ctrl + K Ctrl + K に、行末まで削除を割り当て。
◎ Scriptの修正。 :
Script を使って、Windows上でPythonスクリプトを実行しようとすると、最初の1行目の「#! /usr/bin/env python」(シバン、shebang)を読み取ってエラーが出てしまうので、該当行を無視するように修正。
C:\Users\ユーザ名\.atom\packages\script\lib\script-view.coffee 内の、getShebang というメソッド内で、何も処理をせずに return するようにした。
C:\Users\ユーザ名\.atom\packages\script\lib\script-view.coffee 内の、getShebang というメソッド内で、何も処理をせずに return するようにした。
[ ツッコむ ]
#3 [emacs] NTEmacsの設定を見直し
NTEmacs上でも Pythonスクリプトを書けるようにしたい。以前も設定はしていたらしいのだけど、Pymacs や python-mode が随分古い版を使ってたので、現行版に差し替えてみたり。
Windows上での Pymacs インストールは、 _Pymacs install for windows - ブログ for programming を参考に作業しました。ありがたや。
python-mode は、M-x list-packages だったか、M-x package-list-packages と打って、python-mode を探してインストールして(i を押してから x、だったような…)、古い版をアンインストールしたような…。たしかそのはず。
Windows上での Pymacs インストールは、 _Pymacs install for windows - ブログ for programming を参考に作業しました。ありがたや。
python-mode は、M-x list-packages だったか、M-x package-list-packages と打って、python-mode を探してインストールして(i を押してから x、だったような…)、古い版をアンインストールしたような…。たしかそのはず。
[ ツッコむ ]
以上、1 日分です。