Pythonで図形のドラッグ&ドロップ

  • 2008/08/19(火) 06:02:12

Python->Tkinter->Canvasでオブジェクトをドラッグ&ドロップします。

下記のページを参考にしました。
http://www.shido.info/py/tkinter10.html

上記のページのtoy.pyのドラッグ&ドロップの機能だけを抜き出してシンプルにすると、こうなる。

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:
32:
33:
34:
35:
import Tkinter
 
class CanvasOval:
canvas = None
 
def __init__(self, x0, y0, x1, y1, **key):
self.id = self.canvas.create_oval(x0, y0, x1, y1, **key)
self.canvas.tag_bind(self.id, '<1>', self.drag_start)
self.canvas.tag_bind(self.id, '', self.dragging)
 
def drag_start(self, event):
self.x = event.x
self.y = event.y
 
def dragging(self, event):
self.canvas.move(self.id, event.x-self.x ,event.y-self.y)
self.x = event.x
self.y = event.y
 
class Frame(Tkinter.Frame):
 
def __init__(self, master=None):
Tkinter.Frame.__init__(self, master)
self.cvs = Tkinter.Canvas(self,width="200", height="200", bg="white")
self.cvs.grid(row=0, column=0)
 
CanvasOval.canvas=self.cvs
CanvasOval(40, 40, 50, 50, fill="red", width=0)
CanvasOval(130, 130, 170, 170, fill="red", width=0)
 
if __name__ == '__main__':
f = Frame()
f.pack()
f.mainloop()
 

up_20080819053815.jpg

オブジェクトの移動はCanvasのメソッドであるmoveを使います(16行目)。

moveで動かすオブジェクトの指定はid、またはtagによって判別します。idはオブジェクトを生成した時点で勝手に作られ、7行目のように取得します。tagは複数のオブジェクトを動かす時に使われ、オブジェクトを生成する時にオプションで指定します。

例えば
canvas.create_oval(x0, y0, x1, y1, tags="daen")
でdaenというタグ名がつけられ、
canvas.move("daen", x ,y)
でdaenタグのついたオブジェクト全部をmoveします。

マウスの当たり判定をtag_bindでつけます。指定したidまたはtagに対して設定されます。
バインディングについては以下を参考に。
http://d.hatena.ne.jp/Cassiopeia/20070821/1187701922

よくわかってないのは、27行目。インスタンス変数にぶち込んでるわけでもなく、クラスに直接ぶち込めるの?なんか違和感。いや、まぁ、便利だけど。

目次へ

Pythonでベジエ曲線

  • 2008/08/16(土) 08:33:44

Python->Tkinter->Canvasで2次ベジエ曲線描きます。

標準ではないっぽい。ググったら以下のページを見つけました。
http://www.pygame.org/wiki/BezierCurve?parent=CookBook

よく見るとcalculate_bezier関数で自前で計算しているので、こいつを使わせてもらうことにしました。中身ははさっぱりわからない。
http://www.niksula.cs.hut.fi/~hkankaan/Homepages/bezierfast.html
こちらを参考にしているらしい。ライセンスは・・、Pygameで使ってるってことは少なくともLGPLはokなはず。えと、よくわからん。

vec2dはよく分からんけど、

>>>from vec2d import *
>>>a = vec2d(100,100) + vec2d(50,50)
>>>print a
vec2d(150,150)
>>>b = vec2d(100,100) * vec2d(5,5)
>>>print b
vec2d(500,500)
で、xとyを独立に計算してるだけっぽいので、リストでもいいやってと思ってリストでやった。

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:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
import Tkinter
 
def calculate_bezier(p, steps = 30):
"""
Calculate a bezier curve from 4 control points and return a
list of the resulting points.
 
The function uses the forward differencing algorithm described here:
http://www.niksula.cs.hut.fi/~hkankaan/Homepages/bezierfast.html
"
""
 
t = 1.0 / steps
temp = t*t
 
f = p[0]
fd = 3 * (p[1] - p[0]) * t
fdd_per_2 = 3 * (p[0] - 2 * p[1] + p[2]) * temp
fddd_per_2 = 3 * (3 * (p[1] - p[2]) + p[3] - p[0]) * temp * t
 
fddd = fddd_per_2 + fddd_per_2
fdd = fdd_per_2 + fdd_per_2
fddd_per_6 = fddd_per_2 * (1.0 / 3)
 
points = []
for x in range(steps):
points.append(f)
f = f + fd + fdd_per_2 + fddd_per_6
fd = fd + fdd + fddd_per_2
fdd = fdd + fddd
fdd_per_2 = fdd_per_2 + fddd_per_2
points.append(f)
return points
 
def main():
 
window = Tkinter.Tk()
canvas = Tkinter.Canvas(window, bg = "white",width = 300, height = 200)
canvas.pack()
 
#point = [start_p,control_p1,control_p2,end_p]
point = [[3,30],[150,10],[150,130],[240,140]]
 
#draw dot
for i in range(len(point)):
canvas.create_oval(point[i],point[i],outline = "red", width = 5)
 
#draw line
sl = [[point[0][0],point[0][1],point[1][0],point[1][1]],
[point[1][0],point[1][1],point[2][0],point[2][1]],
[point[2][0],point[2][1],point[3][0],point[3][1]]]
canvas.create_line(sl,fill="red",width=1)
 
#draw curve
pp = [point[0][0],point[1][0],point[2][0],point[3][0]]
sp = [point[0][1],point[1][1],point[2][1],point[3][1]]
pp = calculate_bezier(pp)
sp = calculate_bezier(sp)
 
ll=[]
for i in range(len(pp)-1):
tl = [pp[i],sp[i],pp[i+1],sp[i+1]]
ll = ll + tl
 
canvas.create_line(ll,fill="green",width=3)
window.mainloop()
 
 
if __name__ == '__main__':
main()
 

up_20080816082613.jpg

けど、数値関係はArrayの方が速いらしいのでArrayでやった方がいいのかも。こんぐらいじゃ変わらないかなぁ。

目次へ

Pythonでスプライン曲線

  • 2008/08/16(土) 00:26:28

Python->Tkinter->Canvasにスプライン曲線描きます。普通にCanvasオブジェクトで用意されているので簡単です。

create_line(x1,y1,x2,y2,x3,y3)
で直線ですが、

create_line(x1,y1,x2,y2,x3,y3,smooth=True)
でスプライン曲線になります。splinestepsで細かさを設定できます。デフォルトは12らしい。

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
import Tkinter
 
def main():
 
window = Tkinter.Tk()
canvas = Tkinter.Canvas(window, bg = "white",width = 300, height = 200)
canvas.pack()
#spline
canvas.create_line(30,30,150,30,150,130,240,140,
fill="green",width=3,smooth=True,splinesteps=30)
#line
canvas.create_line(30,30,150,30,150,130,240,140,
fill="red",width=1)
window.mainloop()
 
 
if __name__ == '__main__':
main()
 

up_20080816010710.jpg

その他create_lineについてはこちらが参考になります。
http://kansai.anesth.or.jp/gijutu/python/man-gui/man-canvas.php#c-create_line

なんでこんな簡単なことをわざわざ書いたかと言うと、最初知らなくて自前で関数を作るしかないなっと思って、苦手な数学と格闘して、負けて惨めな気分になったからだ。むきゃー。

参考
http://www.pythonware.com/library/tkinter/introduction/x2102-methods.htm

目次へ

Pythonでドローソフト制作

  • 2008/08/15(金) 14:49:23

製作過程を載せると公言しておきながら、まったく書いていないのですが、とりあえず目次的なものを。自分用に。でも、ソースを晒すってのは、抵抗がありますな〜。こんなクソソースを晒していいものか・・。

今のところの最終的な目標は、ベクタ画像のモーフィングによって簡単なアニメーションを作れること(Flashみたいな)で、流れとして、まず線画ツールを目指し、その後タイムラインを実装しモーフィングを可能に、できたら彩色機能を追加という感じで考えています。(彩色はGimpなどで連番処理させればいいんじゃね?と思うところもあるので、あまりやる気なし。つーかむずそう)

基本的にはTkinterでやっていくつもりですが、面倒ならwxPythonとか他のGUIキットも使うかも。
尚、この投稿は進み具合で随時変更します。

ちなみに僕はド素人です。ここでの情報はむしろ教えを請いたいがために書いてるようなものなので、初心者の方、間に受けないように。間違いや阿呆なやり方をしていたら指摘してほしいです。

現状



基本
スプライン曲線を描く
2次ベジエ曲線を描く
オブジェクトのドラッグ&ドロップ
・オブジェクトの削除
・画像の保存

1.線画ツール制作 製作過程
・GUIベース
・オブジェクトクラスとアンカークラス
・曲線の描写
・アンカーの追加
・アンカーのドラッグ
・アンカーの削除
・EditモードとObjectモードの切り替え
・オブジェクトの選択
・オブジェクトのドラッグ
・オブジェクトの削除
・線の色の変更
・線の太さの変更
・線の部分的な太さの変更 ←いまここ
                  (以下はToDo)
・オブジェクトの回転
・選択アンカーの回転
・オブジェクトの拡大縮小
・選択アンカーの拡大縮小
・アンカーの分割
・キャンバスの拡大縮小表示
・キャンバスのドラッグ
・オブジェクトの開閉の切り替え
・アンカーの鋭鈍の切り替え
・独自形式の保存
・ラスタ画像の出力
・ベクタ画像の出力
・マルチオブジェクト編集
・レイヤ機能(グループ化)
・アンドゥ・リドゥ
・自由曲線のドラッグ描写
・ユーザインターフェイス

ソースコードをHTMLで色分け表示

  • 2008/08/09(土) 23:23:26

ブログにソースコードを載せるに当たって、色分けを気軽にできるようにwebアプリなんぞ組んでみました。組んだってゆーか、現存のライブラリを使ったので、組んだってレベルじゃないんですが^^;
使いたい人がいれば、どんぞー。

http://academic.meganebu.com/~tibra/script/single/color_code.php
http://timidity-f.vndv.com/script/single/color_code.php


GeSHiっていうライブラリ使ってます。
http://qbnz.com/highlighter/

行数表示はtableタグで区分けしてるだけです。CSS+JavaScriptで表示する方法が分からない人(自分)用。



他にブログでソースコードを色分けする方法として、JavaScriptでクライアント側で色分けする方法があるらしい。

dp.SyntaxHighlighter-コード表示に役立つJavaScript
http://weblibrary.s224.xrea.com/weblog/web20/blog/dpsyntaxhighlig.html

SHJS - Syntax Highlighting in JavaScript
http://shjs.sourceforge.net/
highlight.js
http://softwaremaniacs.org/soft/highlight/en/