🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1970閲覧

canvas 複数色変え

goki_gottan

総合スコア168

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/12/08 11:28

現在、canvasを使用して、複数の丸を書いております。
やりたい事は、ある処理が終わったら次のcanvasの色を変えたいと思ってます。

canvas1、canvas2、、canvas100と、100個同じ丸の図形を作りました。位置は別々なのですが、今回の質問と逸れますが他の方法があれば教えてください。それぞれ位置の違う100個の同じ丸の作り方について。

本題に入ります。その100個の丸を、
ある処理が終われば、canvas1の色を変え、次に、ある処理が終わればcanvas2の色が変わり、という感じで、canvas100まで同様な処理で色を変えたく思います。

処理は、tkinter内で、for文で回しており、canvasの数が少なければ、指定してconfigで変えれば良いですが、100個はさすがにコードを書くのは無理です。
そこで、変数の代入、exec、fomatなど使ってみて、文字列として、canvasの後ろの数値をfor文で変えて、その後、変数変換を試しましたが、色が変わりませんでした。

つきまして、canvas1からcanvas100を、うまく変数を変えながら、色変えする方法を教えてください。

また、canvas1からcanvas100を一括して、色変えの方法もあわせてご教示いただけないでしょうか?

そもそもcanvas1からcanvas100まで作らなくても、一括管理でき、かつ、各それぞれ、処理ごとに一個ずつ色変えする方法をご教示いただけないでしょうか?

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teamikl

2020/12/08 12:18

コードを掲載できますか? canvas1, ... canvas100 は、円の数のことだと思いますが、 キャンバスの数が100個だと前提が変わってきます。
guest

回答2

0

tkinter内で、for文で回しており、canvasの数が少なければ、指定してconfigで変えれば良いですが、100個はさすがにコードを書くのは無理です。

mainloop 実行以降は、例えばイベントハンドラ内の関数内では
可能な限りループ文は避けたほうが良いです。

描画の更新は関数の実行が終わってからなので、
ループに時間がかかる場合は、GUI操作の遅延になることがあります。

どうしても描画の更新が必要な場合のみ、
ループ内で update_idletasks を呼び出して即時に描画を更新も出来ますが、
大抵の場合はタイマーを使って実装する方法をお勧めします。

そこで、変数の代入、exec、fomatなど使ってみて、文字列として、canvasの後ろの数値をfor文で変えて、その後、変数変換を試しましたが、色が変わりませんでした。

変数で管理するのではなく、描画する円に tag を付けて
itemconfigure で色等の情報を変更する方法があります。

補足追記: 個別の識別子としてタグを付けるのではなく、
同じ色の円に同じタグを付ける事で、そのタグがついてる円の色を一斉に変えることが出来ます。

投稿2020/12/08 12:32

編集2020/12/08 12:47
teamikl

総合スコア8738

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

goki_gottan

2020/12/09 07:45

ご回答ありがとうございます。 GUIで、同様な作業をどうしてもさせたく、For文を使用しております。 update_idletasks  調べてみます。after構文を使ってみましたが、うまくいきませんね。 タグ付けというのは、 canvas1、canvas2とか作らず、canvas. ・・・にして、【】内のtag名を1、2にすればいいということでしょうか? canvas.create_oval(10, 10, 140, 140, tag="oval_1") canvas.create_oval(10, 10, 140, 140, tag="oval_2") でも、この場合、canvas.placeをどのように指定するのでしょうか? この色指定と、即時色変えがうまくいけばベストアンサーにさせていただきたく思います
teamikl

2020/12/09 08:14 編集

質問の回答にも書きましたが、前提になってるコードが解らないので、 「この場合、canvas.place を~」は良く解りません。 私の回答の想定では、「canvas 内に複数の円を描画」だと思って書いてるので、 place は全く関係ないのですが、 円描画一つに1つのキャンバスを作り、多数のキャンバスを place で各所に配置のようなことをされてますか?
goki_gottan

2020/12/09 08:22

canvasの書き方は以下にしてます。 canvas1=tkinter.Canvas(frame,width=100,height=200) canvas1.create_oval(10,10,80,80,tag="oval",fill="blue") canvas1.place(x=100,y=500) canvas2=tkinter.Canvas(frame,width=100,height=200) canvas2.create_oval(10,10,80,80,tag="oval",fill="blue") canvas2.place(x=200,y=500) こんなのを100個つくりました。 そうでないと、それぞれ1個ずつ処理によって色変えできないと思いましたので。
teamikl

2020/12/09 08:23

> 作業をどうしてもさせたく、For文を使用しております。 作業内容次第ですが、GUIと関連のないタスクなら別スレッドで、 アニメーション用途ならtkinterの タイマーを使った方が良いです。 update_idletabks (描画のみ更新) もしくは update (描画更新 + イベント処理)を ループ内で呼び出す事で、時間の掛かる for 文でGUIがフリーズするのを回避できます が、妥協策的な対応です。(影響: ループで行う処理自体が、より時間がかかるようになってしまう)
teamikl

2020/12/09 08:26

コード内容把握しました、後者の円一つづつにキャンバスを作ってたのですね。 キャンバスを一つにすることは可能ですか? > それぞれ1個ずつ処理によって色変えできないと思いましたので。 の点については、回答した方法で個別に色変え可能です。
goki_gottan

2020/12/09 08:29

別スレッドとは、別関数として処理という事でしょうか。 ボタンを押すと、テキストボックス内に記入した数値を条件として、その数値を使い、ある機器を動かしております。その機器に複数回動作させて、その機器から値を読み取り、最終的にその数値をcsv出力させる予定で、tkinter自体は、動作中とくに必要ないですが、進行を見せたく、canvasの図形に色を変えていこうと思っております。 tkinterとは別処理というのが、いまいち理解しがたいのですが、def アクション(ボタンイベント)関数で、機器へ接続し、処理させております。そのdef アクション(ボタンイベント)関数内にreturn breakを設置しておりますが、どういった構文がいいんでしょうか。
goki_gottan

2020/12/09 08:32

>回答した方法で個別に色変え可能です。 tagを分ければ済むのでしょうか? その際のplaceはどのように設定するのでしょうか。
goki_gottan

2020/12/09 08:36

canvas=tkinter.Canvas(frame,width=600,height=800) canvas.create_oval(10,10,80,80,tag="oval1",fill="blue") canvas.place(x=100,y=500) canvas.create_oval(10,10,80,80,tag="oval2",fill="blue") canvas.place(x=200,y=500) こんな感じでできるのでしょうか?
goki_gottan

2020/12/09 08:39

↑上記の方法では、すべてx=200,y=500で重なりますね。tagに対してplaceしないといけないようですね
teamikl

2020/12/09 08:42

place の利用がそもそも解りません(私の視点からはコードの全体像を把握できないので - create_oval(10,10,80,80,tag="oval2",fill="blue") の 10, 10, 80, 80 が円の収まる座標です - canvas.place はキャンバスが配置される座標です
guest

0

ベストアンサー

コード投稿の為別投稿にて回答します。
キャンバスを複数作られてるようですが、

  • 一つのキャンバス内に複数の円を描画
  • タグは複数付けられるので、共通のタグをつければ一括変更も可
  • タグの代わりに create_oval の戻り値、個別の円の識別に使えます。

python

1import tkinter as tk 2 3root = tk.Tk() 4canvas = tk.Canvas(root, width=800, height=600) 5canvas.pack(fill=tk.BOTH, expand=tk.YES) 6 7canvas.create_oval(100, 100, 200, 200, fill="black", tag=("circle", "c1")) 8canvas.create_oval(200, 100, 300, 200, fill="black", tag=("circle", "c2")) 9canvas.create_oval(300, 100, 400, 200, fill="black", tag=("circle", "c3")) 10 11def start_tasks(): 12 import time 13 for item in ["c1", "c2", "c3"]: 14 time.sleep(1) # XXX: 時間の掛かる処理。 15 # 動作デモの為、時間の掛かる処理の代わりとして time.sleep を使いますが、 16 # tkinter のイベントが処理されなくなるので、実際のアプリケーションでは使ってはいけない。 17 18 canvas.itemconfig(item, fill="green") # 色変更 19 canvas.update_idletasks() # 描画更新 20 21button1 = tk.Button(root, text="start tasks", command=start_tasks) 22button1.pack() 23 24def onclick(): 25 canvas.itemconfig("circle", fill="black") 26button2 = tk.Button(root, text="reset", command=onclick) 27button2.pack() 28 29root.mainloop()

投稿2020/12/09 09:06

teamikl

総合スコア8738

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

goki_gottan

2020/12/09 10:59

canvasの設定の仕方わかりました。ありがとうございます。 これならc1、c2のようなtagをfor文で100個近く作れそうですね。 色変えに関してもfor文で回せますね。 あとは、time.sleepがいらないですよね。即時にしたく思います。 その場合、time.sleep(0)にした方がいいのでしょうか。 time.sleepなしで、canvas.update_idletasks() これって動作しますか?
teamikl

2020/12/09 12:11

time.sleep 自体を削除してしまって大丈夫です。 進捗確認専用のGUIなら関係ないかもしれませんが、 time.sleepをボタンを押されたときに呼ばれる関数内で使うと、 その間は tkinter はフリーズして入力等を受け付けない状態になってます。 > time.sleepなしで、canvas.update_idletasks() これって動作しますか? 問題ありません ループ処理の回数次第では、10回に一回呼ぶ等、適度に間引いた方が良いかもしれません。 update_idletasks の分が遅延になり、数千数万回規模になってくると処理時間自体に影響します。 そこ迄完成すれば、次のステップとして、(必要があれば) スレッドの導入を検討して見て下さい。 スレッド側で実行する関数ではループ文の利用やtime.sleep を利用しても問題ないので、 より効率的な方法で実装出来ます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問