|
|
TkDocs_Tk Canvas. |
H.Kamifuji . |
キャンバスウィジェットは、線、円、画像、その他のウィジェットなどのグラフィカルオブジェクトの2Dコレクションを管理します。 Tk のキャンバスは信じられないほど強力で柔軟なウィジェットであり、本当に Tk のハイライトの1つです。 これは、図面や図形作成、CAD ツール、シミュレーションや実際の機器の表示や監視、より単純なものからより複雑なウィジェットを構築するための幅広い用途に適しています。 キャンバスウィジェットはテーマ Tk ウィジェットではなく、古典的なTkウィジェットの一部です。![]() perl Tkx : キャンバスウィジェットは、new_tk__canvasメソッドa.k.a. Tkx :: tk__canvasを使用して作成されます。 $canvas = $parent->new_tk__canvas();Python : Canvasウィジェットは、Canvas関数を使用して作成されます。 canvas = Canvas(parent)キャンバスウィジェットには膨大な機能が含まれているので、ここではすべてをカバーすることはできません。 私たちがやることは、かなり簡単な例(フリーハンドのスケッチツール)を取って、少しずつ新しいものを追加することです。それぞれは新しいキャンバスウィジェットの新機能を示しています。 この章の最後に、この例では説明していないその他の主な機能のいくつかについて説明します。 |
新しいキャンバスウィジェットを作成すると、それは基本的に何もない大きな矩形になります。 真に空白のキャンバス、つまり言い換えれば。 便利なことをするには、項目を追加する必要があります。 前述したように、さまざまな種類のアイテムを追加できます。 ここでは、単純な広告申込情報をキャンバスに追加する方法について説明します。 行を作成するには、指定する必要がある情報の1つが、行がどこにあるのかです。 これは、始点と終点の座標を使用して、x0 y0 x1 y1という形式のリストとして表されます。 原点 (0,0) はキャンバスの左上隅にあり、右に移動すると x 値が増加し、下に移動するとy値が増加します。 したがって、 (10,10) から (200,50) までの行を作成するには、次のコードを使用します。 perl Tkx : $canvas->create_line(10,10,200,50);"create_line" メソッドは、このアイテムを一意に参照するために使用できるアイテムID(整数)を返します。 作成されたすべてのアイテムは独自のIDを取得します。 あとで項目を参照する必要はない場合が多いので、返されたIDは無視されますが、すぐに使用できる方法がわかります。 Python : canvas.create_line(10, 10, 200, 50)"create_line" メソッドは、このアイテムを一意に参照するために使用できるアイテムID(整数)を返します。 作成されたすべてのアイテムは独自のIDを取得します。 あとで項目を参照する必要はない場合が多いので、返されたIDは無視されますが、すぐに使用できる方法がわかります。 簡単なスケッチパッドの例を始めましょう。 今のところ、キャンバス上にマウスをドラッグしてフリーハンドを描くことができるようにしたいと考えています。 キャンバスウィジェットを作成し、イベントバインディングをアタッチしてマウスのクリックやドラッグをキャプチャします。 最初にマウスをクリックすると、その位置が "start" 位置として記憶されます。 マウスボタンを押したままマウスを移動するたびに、この「開始」位置から現在のマウス位置に移動する広告申込情報が作成されます。 現在の位置は、次の線分の「開始」位置になります。 perl Tkx : use Tkx; $mw = Tkx::widget->new("."); $canvas = $mw->new_tk__canvas; $canvas->g_grid(-column=>0, -row=>0, -sticky=>"nwes"); $mw->g_grid_columnconfigure(0, -weight=>1); $mw->g_grid_rowconfigure(0, -weight=>1); $canvas->g_bind("<1>", [sub {my ($x,$y) = @_; $lastx=$x; $lasty=$y}, Tkx::Ev("%x","%y")]); $canvas->g_bind("<B1-Motion>", [sub {my ($x,$y) = @_; addLine($x,$y)}, Tkx::Ev("%x","%y")]); sub addLine { my ($x,$y) = @_; $canvas->create_line($lastx,$lasty,$x,$y); $lastx = $x; $lasty = $y; } Tkx::MainLoop();Python : from tkinter import * from tkinter import ttk lastx, lasty = 0, 0 def xy(event): global lastx, lasty lastx, lasty = event.x, event.y def addLine(event): global lastx, lasty canvas.create_line((lastx, lasty, event.x, event.y)) lastx, lasty = event.x, event.y root = Tk() root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) canvas = Canvas(root) canvas.grid(column=0, row=0, sticky=(N, W, E, S)) canvas.bind("それを試してみてください - キャンバスの周りにマウスをドラッグして傑作を作りましょう。 |
アイテムを作成するときには、アイテムの属性を1つ以上指定することもできます。これは、アイテムの表示方法に影響します。 たとえば、ここでは、線が赤で、幅が3ピクセルであることを指定します。 perl Tkx * $canvas->create_line(10, 10, 200, 50, -fill => "red", -width => 3);Python : canvas.create_line(10, 10, 200, 50, fill='red', width=3)属性の正確なセットは、アイテムのタイプによって異なります。 Tk ウィジェットと同様に、キャンバスアイテムを既に作成した後に属性を変更することもできます。 perl Tkx : $id = $canvas->create_line(0, 0, 10, 10, -fill => "red"); ... $canvas->itemconfigure($id, -fill => "blue", -width => 2);Python : id = canvas.create_line(0, 0, 10, 10, fill='red') ... canvas.itemconfigure(id, fill='blue', width=2) |
他の Tk ウィジェットと同様に、キャンバスウィジェット全体が "bind" コマンドを使用してイベントをキャプチャできることは、既に見てきました。 また、キャンバス内の個々のアイテム(またはタグのグループを参照してください)にバインディングを添付することもできます。 そのため、特定のアイテムがクリックされたかどうかを知りたければ、キャンバス全体のマウスクリックイベントを監視する必要はなく、そのアイテムがクリックされたかどうかを調べる必要があります。 Tk はあなたのためにこれをすべて世話します。 これらのイベントをキャプチャするには、キャンバスに組み込まれたバインドコマンドを使用します。 これは、通常のbindコマンドとまったく同じように動作し、イベントパターンとコールバックをとります。 唯一の違いは、このバインディングが適用されるキャンバスアイテムを指定することです。 perl Tkx : $canvas->bind($id, "<1>", sub{...})アイテム固有の "bind" メソッドとウィジェットレベルの "g_bind" メソッドの違いに注意してください Python : canvas.tag_bind(id, '<1>', ...)アイテム固有の "tag_bind"メソッドとwidgetlevel "bind"メソッドの違いに注意してください スケッチパッドの例にコードを追加して、描画色を変更できるようにしましょう。 最初に、それぞれが異なる色で塗りつぶされたいくつかの異なる矩形アイテムを作成します。 矩形アイテムを作成することは、広告アイテムを作成するのと同じです。ここでは、対角にある2つのコーナーの座標を指定します。 次に、これらをクリックすると、グローバル変数を使用する色に設定します。 私たちのマウスモーションバインディングは、線分を作成するときにその変数を調べます。 perl Tkx : $canvas->g_bind("<1>", [sub {my ($x,$y) = @_; $lastx=$x; $lasty=$y}, Tkx::Ev("%x","%y")]); $canvas->g_bind("Python : color = "black" def setColor(newcolor): global color color = newcolor def addLine(event): global lastx, lasty canvas.create_line((lastx, lasty, event.x, event.y), fill=color) lastx, lasty = event.x, event.y id = canvas.create_rectangle((10, 10, 30, 30), fill="red") canvas.tag_bind(id, " |
すべてのキャンバスアイテムには一意の ID 番号が付いていますが、キャンバス上のアイテムを参照するもう1つの非常に便利で強力な方法があり、タグを使用しています。 タグはあなたの作成の識別子です。あなたのプログラムにとって意味のあるものです。キャンバスアイテムにタグを付けることができます。各項目は任意の数のタグを持つことができます。各アイテムに固有のアイテム ID 番号とは異なり、多くのアイテムは同じタグを持つことができます。 あなたはタグで何ができますか?アイテムIDを使用してキャンバスアイテムを変更できることがわかりました(アイテムの移動や削除など、アイテムにできることがすぐにあります)。アイテム ID を使用できるときはいつでも、タグを使用できます。たとえば、特定のタグを持つすべてのアイテムの色を変更できます。 タグは、キャンバス内の特定のタイプのアイテム(描画された線の一部であるアイテム、パレットの一部であるアイテムなど)を識別するのに適した方法です。タグを使用して、アプリケーション内の特定のオブジェクトにキャンバスアイテムを関連付けることができます(たとえば、ロボット#37 のロボットの一部であるすべてのキャンバスアイテムにタグ "robot37" を付けてタグ付けする)。タグを使用すると、後でアイテムのグループを参照するキャンバスアイテムの ID を追跡する必要はありません。タグはあなたにTkをさせます。 "tags" アイテム設定オプションを使用して、アイテムを作成するときにタグを割り当てることができます。後でタグを "addtag" メソッドで追加したり、 "dtags" メソッドでタグを削除したりすることができます。 "gettags" メソッドを使用して項目のタグのリストを取得するか、"find" コマンドを使用して、指定されたタグを持つ項目 ID 番号のリストを返すことができます。 例えば: perl Tkx : Perl> $c = $mw->new_canvas() .c Perl> $c->create_line(10, 10, 20, 20, -tags => "firstline drawing") 1 Perl> $c->create_rectangle(30,30,40,40, -tags => "drawing") 2 Perl> $c->addtag("rectangle", "withtag", 2) Perl> $c->addtag("polygon", "withtag", "rectangle") Perl> $c->gettags(2) drawing rectangle polygon Perl> $c->dtag(2,"polygon") Perl> $c->gettags(2) drawing rectangle Perl> $c->find_withtag("drawing") 1 2Python : >>> c = Canvas(root) >>> c.create_line(10, 10, 20, 20, tags=('firstline', 'drawing')) 1 >>> c.create_rectangle(30, 30, 40, 40, tags=('drawing')) 2 >>> c.addtag('rectangle', 'withtag', 2) >>> c.addtag('polygon', 'withtag', 'rectangle') >>> c.gettags(2) ('drawing', 'rectangle', 'polygon') >>> c.dtag(2, 'polygon') >>> c.gettags(2) ('drawing', 'rectangle') >>> c.find_withtag('drawing') (1, 2)ご覧のように、"withtag" のようなものは、個々の項目またはタグのいずれかを取ります。 後者の場合、タグを持つすべての項目に適用されます(タグなし)。 "addtag" と "find" には他の多くのオプションがあり、ポイントの近くにアイテムを指定したり、特定のエリアをオーバーラップさせたりすることができます。 最初にタグを使用して、現在選択されているカラーパレットのいずれかの項目の周りに境界線を置いてみましょう。 perl Tkx : $id = $canvas->create_rectangle(10, 10, 30, 30, -fill => "red", -tags => "palette palettered"); $id = $canvas->create_rectangle(10, 35, 30, 55, -fill => "blue", -tags => "palette paletteblue"); $id = $canvas->create_rectangle(10, 60, 30, 80, -fill => "black", -tags => "palette paletteblack paletteSelected"); sub setColor { my ($newcolor) = @_; $color = $newcolor; $canvas->dtag_all("paletteSelected"); $canvas->itemconfigure("palette", -outline => "white"); $canvas->addtag("paletteSelected", withtag => "palette".$color); $canvas->itemconfigure("paletteSelected", -outline => "#999999"); } setColor "black"; $canvas->itemconfigure("palette", -width => 5);Python : def setColor(newcolor): global color color = newcolor canvas.dtag('all', 'paletteSelected') canvas.itemconfigure('palette', outline='white') canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color) canvas.itemconfigure('paletteSelected', outline='#999999') id = canvas.create_rectangle((10, 10, 30, 30), fill="red", tags=('palette', 'palettered')) id = canvas.create_rectangle((10, 35, 30, 55), fill="blue", tags=('palette', 'paletteblue')) id = canvas.create_rectangle((10, 60, 30, 80), fill="black", tags=('palette', 'paletteblack', 'paletteSelected')) setColor('black') canvas.itemconfigure('palette', width=5)タグを使って、描画している現在のストロークをより目立たせるようにしましょう。 マウスを放すと正常に戻ります。 perl Tkx : $canvas->g_bind("Python : def addLine(event): global lastx, lasty canvas.create_line((lastx, lasty, event.x, event.y), fill=color, width=5, tags='currentline') lastx, lasty = event.x, event.y def doneStroke(event): canvas.itemconfigure('currentline', width=1) canvas.bind("<B1-ButtonRelease>", doneStroke) |
項目の設定オプション(色、幅など)を変更する方法を見てきました。あなたが項目を行うことができる他の多くのものがあります。 アイテムを削除するには、"delete" メソッドを使用します。アイテムのサイズと位置を変更するには、 "coords" メソッドを使用します。これにより、アイテムの新しい座標を指定することができます。アイテムの最初の作成時と同じ方法で指定します。このメソッドを新しい座標セットなしで呼び出すと、アイテムの現在の座標が返されます。 1 つまたは複数のアイテムを現在の場所から特定の水平または垂直方向に移動するには、 "move" メソッドを使用できます。 すべてのアイテムは、上から順にスタック順と呼ばれます。積み重ね順序の後の項目がその下の項目の座標と重なっている場合、上の項目は下の項目の上に描画されます。 "raise" および "lower" 方法では、積み重ね順にアイテムの位置を調整できます。 リファレンスマニュアルのページには、項目を変更したり、項目に関する追加情報を検索するための操作がいくつか追加されています。 |
多くのアプリケーションでは、キャンバスが画面上に表示されるものより大きくなるようにします。 "xview" と "yview" メソッドを使って通常の方法でキャンバスに水平スクロールバーと垂直スクロールバーを付けることができます。 キャンバスのサイズまでは、キャンバスのサイズを画面上に表示する方法と、キャンバスのフルサイズを指定することができます。表示するにはスクロールが必要です。キャンバスウィジェットの "width" と "height" の設定オプションは、ジオメトリマネージャから所定量のスペースを要求します。 "scrollregion" 構成オプション ( "0 0 1000 1000" など)は、キャンバス表面の大きさをTkに伝える。 既に知っていることを考えれば、スケッチパッドプログラムを変更してスクロールを追加できるはずです。試してみる。 これを済ませたら、少しだけキャンバスをスクロールしてから描画してみてください。あなたが描いている線が、マウスが指しているところの上に現れることがわかります!驚いた? グローバルな "bind" コマンドは、キャンバスがスクロールされていることを知らない(特定のウィジェットの詳細を知らない)ということです。したがって、キャンバスを 50 ピクセル下にスクロールして、左上隅をクリックすると、バインドは (0,0) でクリックしたことを報告します。しかし、スクロールのために、その位置は本当に (0,50) になるはずです。 "canvasx" と "canvasy" メソッドは、スクロールを考慮に入れて、スクリーン上の位置(バインドしている)をキャンバス上の実際のポイントに変換します。これらをイベントバインディングに直接追加する場合は(イベントバインディングから呼び出されるプロシージャではなく)、イベントが発生したときにコンバージョンが確実に行われるように、引用と置換に注意してください。 ここに私たちの完全な例があります。キャンバスをスクロールするとパレットをスクロールしたくないかもしれませんが、別の日にパレットを残しておきます。 perl Tkx : use Tkx; $mw = Tkx::widget->new("."); $canvas = $mw->new_tk__canvas(-scrollregion => "0 0 1000 1000"); $canvas->g_grid(-column=>0, -row=>0, -sticky=>"nwes"); $mw->g_grid_columnconfigure(0, -weight=>1); $mw->g_grid_rowconfigure(0, -weight=>1); $hscroll = $mw->new_tk__scrollbar(-orient => "horizontal", -command => [$canvas, "xview"]); $vscroll = $mw->new_tk__scrollbar(-orient => "vertical", -command => [$canvas, "yview"]); $hscroll->g_grid(-column => 0, -row => 1, -sticky => "we"); $vscroll->g_grid(-column => 1, -row => 0, -sticky => "ns"); $mw->new_ttk__sizegrip()->g_grid(-column => 1, -row => 1, -sticky => "se"); $canvas->configure(-yscrollcommand => [$vscroll, "set"], -xscrollcommand => [$hscroll, "set"]); $canvas->g_bind("<1>", [sub {my ($x,$y) = @_; $lastx=$canvas->canvasx($x); $lasty=$canvas->canvasy($y)}, Tkx::Ev("%x","%y")]); $canvas->g_bind("<B1-Motion>", [sub {my ($x,$y) = @_; addLine($canvas->canvasx($x),$canvas-> canvasy($y))}, Tkx::Ev("%x","%y")]); $canvas->g_bind("<B1-ButtonRelease>", sub {doneStroke();}); $id = $canvas->create_rectangle(10, 10, 30, 30, -fill => "red", -tags => "palette palettered"); $canvas->bind($id, "<1>", sub {setColor("red")}); $id = $canvas->create_rectangle(10, 35, 30, 55, -fill => "blue", -tags => "palette paletteblue"); $canvas->bind($id, "<1>", sub {setColor("blue")}); $id = $canvas->create_rectangle(10, 60, 30, 80, -fill => "black", -tags => "palette paletteblack paletteSelected"); $canvas->bind($id, "<1>", sub {setColor("black")}); sub setColor { my ($newcolor) = @_; $color = $newcolor; $canvas->dtag_all("paletteSelected"); $canvas->itemconfigure("palette", -outline => "white"); $canvas->addtag("paletteSelected", withtag => "palette".$color); $canvas->itemconfigure("paletteSelected", -outline => "#999999"); } setColor "black"; $canvas->itemconfigure("palette", -width => 5); sub addLine { my ($x,$y) = @_; $canvas->create_line($lastx,$lasty,$x,$y, -fill => $color, -width => 5, -tags => "currentline"); $lastx = $x; $lasty = $y; } sub doneStroke { $canvas->itemconfigure("currentline", -width => 1); } Tkx::MainLoop(); ![]() Python : from tkinter import * from tkinter import ttk root = Tk() h = ttk.Scrollbar(root, orient=HORIZONTAL) v = ttk.Scrollbar(root, orient=VERTICAL) canvas = Canvas(root, scrollregion=(0, 0, 1000, 1000), yscrollcommand=v.set, xscrollcommand=h.set) h['command'] = canvas.xview v['command'] = canvas.yview ttk.Sizegrip(root).grid(column=1, row=1, sticky=(S,E)) canvas.grid(column=0, row=0, sticky=(N,W,E,S)) h.grid(column=0, row=1, sticky=(W,E)) v.grid(column=1, row=0, sticky=(N,S)) root.grid_columnconfigure(0, weight=1) root.grid_rowconfigure(0, weight=1) lastx, lasty = 0, 0 def xy(event): global lastx, lasty lastx, lasty = canvas.canvasx(event.x), canvas.canvasy(event.y) def setColor(newcolor): global color color = newcolor canvas.dtag('all', 'paletteSelected') canvas.itemconfigure('palette', outline='white') canvas.addtag('paletteSelected', 'withtag', 'palette%s' % color) canvas.itemconfigure('paletteSelected', outline='#999999') def addLine(event): global lastx, lasty x, y = canvas.canvasx(event.x), canvas.canvasy(event.y) canvas.create_line((lastx, lasty, x, y), fill=color, width=5, tags='currentline') lastx, lasty = x, y def doneStroke(event): canvas.itemconfigure('currentline', width=1) canvas.bind(" ![]() ![]() |
線や四角形の他に、キャンバスウィジェットがサポートするさまざまな種類のアイテムがあります。それぞれには独自の項目設定オプションがあり、リファレンスマニュアルに詳述されています。 "line" タイプのアイテムは、実際には私たちが見たものより少しばかばかしいかもしれません。広告申込情報は、実際には1つではなく一連の線分になることができます。この例では、1 つのストロークごとに 1 つの広告申込情報を使用することができました。また、線をポイントツーポイントで直接描画したり、曲線に滑らかにすることもできます。 私たちが見たタイプのアイテム "rectangle"。 "oval" のアイテムは同じ働きをしますが、楕円形として描画します。 "arc" タイプのアイテムは、楕円の一部を描画することができます。 "polygon" タイプのアイテムは、任意の数の側面を持つ閉じたポリゴンを描画できます。 ピクチャは、"bitmap" (白黒の場合)または "image"(フルカラーの場合)のタイプのアイテムを使用してキャンバスウィジェットに追加できます。 "text" タイプのアイテムを使用してキャンバスにテキストを追加できます。表示される実際のテキストだけでなく、フォント、サイズ、色などを完全に制御できます。 おそらくもっとも興味深いのは、他のウィジェット(他のウィジェットを含むフレームを含む)を「ウィンドウ」タイプの項目を使用してキャンバスに埋め込むことができることです。これを行うと、実際にキャンバスが他のウィジェットのジオメトリマネージャとして機能します。この機能により、アプリケーションのあらゆる可能性が高まります。 キャンバスウィジェットには、ここで説明したよりもはるかに多くのものがあります。リファレンスマニュアルや、Tk ディストリビューションに含まれている広範なサンプルプログラムを参照してください。 |
use Tkx; $mw = Tkx::widget->new("."); $canvas = $mw->new_tk__canvas; $canvas->g_grid(-column=>0, -row=>0, -sticky=>"nwes"); $mw->g_grid_columnconfigure(0, -weight=>1); $mw->g_grid_rowconfigure(0, -weight=>1); $canvas->g_bind("<1>", [sub {my ($x,$y) = @_; $lastx=$x; $lasty=$y}, Tkx::Ev("%x","%y")]); $canvas->g_bind("<B1-Motion>", [sub {my ($x,$y) = @_; addLine($x,$y)}, Tkx::Ev("%x","%y")]); sub addLine { my ($x,$y) = @_; $canvas->create_line($lastx,$lasty,$x,$y); $lastx = $x; $lasty = $y; } Tkx::MainLoop(); ![]() |
from tkinter import * from tkinter import ttk lastx, lasty = 0, 0 def xy(event): global lastx, lasty lastx, lasty = event.x, event.y def addLine(event): global lastx, lasty canvas.create_line((lastx, lasty, event.x, event.y)) lastx, lasty = event.x, event.y root = Tk() root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) canvas = Canvas(root) canvas.grid(column=0, row=0, sticky=(N, W, E, S)) canvas.bind("<Button-1>", xy) canvas.bind("<B1-Motion>", addLine) root.mainloop() ![]() ![]() |
use Tkx; $mw = Tkx::widget->new("."); $canvas = $mw->new_tk__canvas; $canvas->g_grid(-column=>0, -row=>0, -sticky=>"nwes"); $mw->g_grid_columnconfigure(0, -weight=>1); $mw->g_grid_rowconfigure(0, -weight=>1); $canvas->g_bind("<1>", [sub {my ($x,$y) = @_; $lastx=$x; $lasty=$y}, Tkx::Ev("%x","%y")]); $canvas->g_bind("<B1-Motion>", [sub {my ($x,$y) = @_; addLine($x,$y)}, Tkx::Ev("%x","%y")]); $id = $canvas->create_rectangle(10, 10, 30, 30, -fill => "red"); $canvas->bind($id, "<1>", sub {setColor("red")}); $id = $canvas->create_rectangle(10, 35, 30, 55, -fill => "blue"); $canvas->bind($id, "<1>", sub {setColor("blue")}); $id = $canvas->create_rectangle(10, 60, 30, 80, -fill => "black"); $canvas->bind($id, "<1>", sub {setColor("black")}); $color = "black"; sub setColor { my ($newcolor) = @_; $color = $newcolor; } sub addLine { my ($x,$y) = @_; $canvas->create_line($lastx,$lasty,$x,$y, -fill => $color, -width => 5); $lastx = $x; $lasty = $y; } Tkx::MainLoop(); ![]() |
from tkinter import * from tkinter import ttk lastx, lasty = 0, 0 color = "black" def setColor(newcolor): global color color = newcolor def addLine(event): global lastx, lasty canvas.create_line((lastx, lasty, event.x, event.y), fill=color, width=5) lastx, lasty = event.x, event.y def xy(event): global lastx, lasty lastx, lasty = event.x, event.y # def addLine(event): # global lastx, lasty, color # canvas.create_line((lastx, lasty, event.x, event.y)) # lastx, lasty = event.x, event.y root = Tk() root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) canvas = Canvas(root) canvas.grid(column=0, row=0, sticky=(N, W, E, S)) canvas.bind(" ![]() ![]() |
Canvas |
|