質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Tkinter

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

Python

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

Q&A

解決済

4回答

10288閲覧

tkinterが重くなりがち。

akisan55

総合スコア49

Tkinter

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

Python

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

0グッド

1クリップ

投稿2020/07/23 03:19

編集2020/07/23 23:36

###概要
Pythonでtkinterをつかって練習しているのですが、tkinterが重くなりがちです。
左クリックをした時の座標の位置に50x50の正方形を出すプログラムを実行して、
正方形を144個置けるようにしたいのですが、途中プログラムが応答するまで時間がかかりすぎます。
tkinterというのは重くなって当たり前なのでしょうか。
###環境

Python

1certifi 2020.4.5.1 2chardet 3.0.4 3Cython 0.26.1 4docutils 0.16 5idna 2.9 6Kivy 1.11.1 7Kivy-Garden 0.1.4 8numpy 1.19.0 9Pillow 7.1.1 10pip 20.1 11pygame 1.9.6 12Pygments 2.6.1 13python-dateutil 2.8.1 14pytz 2020.1 15requests 2.23.0 16setuptools 28.8.0 17six 1.15.0 18urllib3 1.25.9 19wheel 0.34.2

###コード
コードはリンクします。
https://github.com/akisan55/Python/blob/master/python_game
###補足
独学でPythonを始めたばかりの小学6年生です。
プログラムにおかしいところがあるかもしれません。
宜しくお願いします。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2020/07/23 03:29

tkinter自体はとても軽いものです。プログラムがないとなんとも言えませんが、tkinterはGPUを使用してくれないので、非同期処理等をしなくては重くなります(それはどのライブラリでも同じ)。なので、まずプログラムを見せてください。400字程度ではわかりません。
akisan55

2020/07/23 04:26

コードの一部を追加しました。 宜しくお願いします。
can110

2020/07/23 04:56

一部ではなく実際に「重い」と感じることのできる実行できるコード全体を提示ください。 文字数制限でアップできないのであれば、現象が再現できる修正したコード全体を提示ください。
akisan55

2020/07/23 07:47

何回かに分けてプログラムを送ります。 import tkinter import time import random import numpy root = tkinter.Tk() root.geometry('1540x800') root.title('Multi Color Puzzle') canvas = tkinter.Canvas(root,width = 1540,height = 800, bg = "gold") canvas.place(x = 0,y = 0) index = 0 key = "" def key_down(e): global key,index key = e.keysym if index == 0: if key == "space": canvas.delete("all") label.place_forget() index += 1 main_two() def square(canvas): canvas.create_rectangle(x1,y1,x1+50,y1+50, fill=color) canvas.create_rectangle(x1+30,y1+5,x1+45,y1+10, fill="white",outline="white",width=0) canvas.create_rectangle(x1+40,y1+10,x1+45,y1+20,fill = "white",width=0) canvas.create_rectangle(x1+40,y1+25,x1+45,y1+30,fill = "white",outline="black",width=1) canvas.create_line(x1+30,y1+5,x1+45,y1+5,x1+45,y1+5,x1+45,y1+20,x1+40,y1+20,x1+45,y1+20,fill="black",width=1) canvas.create_line(x1+30,y1+5,x1+30,y1+10,x1+30,y1+10,x1+40,y1+10,x1+40,y1+10,x1+40,y1+20,fill="black",width=1) def now_square(canvas): canvas.create_rectangle(x3,y3,x3+70,y3+70,fill="#E6E6FA",outline="navy",width=4) x2=250 y2=70 def main_one(): global index,key,label if index == 0: label = tkinter.Label(text="SPACE KEY を押してスタート",font=("system",30),bg="gold") label.place(x=550,y=200) def block(): global block_number,brn block_number = random.randint(1,24) brn = block_number list_move = [25,25,25,25,25,25,25,25,25,25,25,25, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 25,25,25,25,25,25,25,25,25,25,25,25] numlist = [] def block_move_sub(): global label2,index,label5,numlist canvas.delete("all") label2 = tkinter.Label(text = "GAMEOVER",font=("system",500),bg="gold") label2.place(x=550,y = 200) label3.place_forget() index += 1 numlist.extend([score]) label5 = tkinter.Label(text = "最高得点は" + str(max(numlist)),font=("system",50)) label5.place(x=10,y=720) label6.place_forget() label7.place_forget() label8.place_forget() label9.place_forget() label10.place_forget() label11.place_forget() label12.place_forget() label13.place_forget() label14.place_forget() label15.place_forget() label16.place_forget() label17.place_forget() label18.place_forget() label19.place_forget() label20.place_forget() label21.place_forget() label22.place_forget() label23.place_forget() label24.place_forget() label25.place_forget() label26.place_forget() label27.place_forget() label28.place_forget() label29.place_forget() root.after(5000,main_two_sub) def block_move(e): global x1,y1,exlist,point_x,point_y,eylist,exlistArray,eylistArray,pos_x,pos_y,score,label6,label7,label8,label9,label10,label11,label12,label13,label14,label15,label16,label17,label18,label19,label20,label21,label22,label23,label24,label25,label26,label27,label28,label29 if index == 1: point_x = e.x point_y = e.y exlist = [495,545,595,645,695,745,795,845,895,945,995,1045] exlistArray = numpy.array(exlist) pos_x = (numpy.abs(exlistArray-point_x)).argmin() eylist = [125,175,225,275,325,375,375,425,475,525,575,625,675] eylistArray = numpy.array(eylist) pos_y = (numpy.abs(eylistArray-point_y)).argmin() exnumber = exlistArray[pos_x] - 25 eynumber = eylistArray[pos_y] - 25 list_number = int(((exnumber - 470) / 50 + (eynumber - 100) / 50 * 12) + 12) if list_move[list_number] == 0: if point_x >= 470 and point_x <= 1070 and point_y >= 100 and point_y <= 700: x1 = exnumber y1 = eynumber square(canvas) list_move[list_number] = brn if list_move[list_number - 1] == brn or list_move[list_number + 1] == brn or list_move[list_number - 12] == brn or list_move[list_number + 12] == brn : root.after(500,block_move_sub) else : score += 3 score_pack() label6.place_forget() label7.place_forget() label8.place_forget() label9.place_forget() label10.place_forget() label11.place_forget() label12.place_forget() label13.place_forget() label14.place_forget() label15.place_forget() label16.place_forget() label17.place_forget() label18.place_forget() label19.place_forget() label20.place_forget() label21.place_forget() label22.place_forget() label23.place_forget() label24.place_forget() label25.place_forget() label26.place_forget() label27.place_forget() label28.place_forget() label29.place_forget() color_determine() else :pass
退会済みユーザー

退会済みユーザー

2020/07/23 07:49

一応PCのスペックも教えてください
akisan55

2020/07/23 07:49

続き a1 = 6 a2 = 6 a3 = 6 a4 = 6 a5 = 6 a6 = 6 a7 = 6 a8 = 6 a9 = 6 a10 = 6 a11 = 6 a12 = 6 a13 = 6 a14 = 6 a15 = 6 a16 = 6 a17 = 6 a18 = 6 a19 = 6 a20 = 6 a21 = 6 a22 = 6 a23 = 6 a24 = 6 def color_determine(): global x1,y1,color,score,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,label6,label7,label8,label9,label10,label11,label12,label13,label14,label15,label16,label17,label18,label19,label20,label21,label22,label23,label24,label25,label26,label27,label28,label29 block() w = "white" x1 = x3+10 y1 = y3+10 if index == 1: if brn == 1 and a1 != 0: a1 -= 1 color = "red" elif brn == 2 and a2 != 0: a2 -= 1 color = "blue" elif brn == 3 and a3 != 0: a3 -= 1 color = "gold" elif brn == 4 and a4 != 0 : a4 -= 1 color = "limegreen" elif brn == 5 and a5 != 0 : a5 -= 1 color = "deeppink" elif brn == 6 and a6 != 0: a6 -= 1 color = "purple" elif brn == 7 and a7 != 0: a7 -= 1 color = "cyan" elif brn == 8 and a8 != 0: a8 -= 1 color = "orange" elif brn == 9 and a9 != 0: a9 -= 1 color = "ivory" elif brn == 10 and a10 != 0: a10 -= 1 color = "navy" elif brn == 11 and a11 != 0: a11 -= 1 color = "violet" elif brn == 12 and a12 != 0: a12 -= 1 color = "indianred" elif brn == 13 and a13 != 0: a13 -= 1 color = "gainsboro" elif brn == 14 and a14 != 0: a14 -= 1 color = "mistyrose" elif brn == 15 and a15 != 0: a15 -= 1 color = "skyblue" elif brn == 16 and a16 != 0: a16 -= 1 color = "khaki" elif brn == 17 and a17 != 0: a17 -= 1 color = "coral" elif brn == 18 and a18 != 0: a18 -= 1 color = "greenyellow" elif brn == 19 and a19 != 0: a19 -= 1 color = "tan" elif brn == 20 and a20 != 0: a20 -= 1 color = "snow" elif brn == 21 and a21 != 0: a21 -= 1 color = "maroon" elif brn == 22 and a22 != 0: a22 -= 1 color = "olive" elif brn == 23 and a23 != 0: a23 -= 1 color = "crimson" elif brn == 24 and a24 != 0: a24 -= 1 color = "green" else: block() root.after(1,color_determine) label6 = tkinter.Label(text="=" + str(a1),font=(10),bg=w) label6.place(x=45,y=285) label7 = tkinter.Label(text="=" + str(a2),font=(10),bg=w) label7.place(x=145,y=285) label8 = tkinter.Label(text="=" + str(a3),font=(10),bg=w) label8.place(x=245,y=285) label9 = tkinter.Label(text="=" + str(a4),font=(10),bg=w) label9.place(x=45,y=325) label10 = tkinter.Label(text="=" + str(a5),font=(10),bg=w) label10.place(x=145,y=325) label11 = tkinter.Label(text="=" + str(a6),font=(10),bg=w) label11.place(x=245,y=325) label12 = tkinter.Label(text="=" + str(a7),font=(10),bg=w) label12.place(x=45,y=365) label13 = tkinter.Label(text="=" + str(a8),font=(10),bg=w) label13.place(x=145,y=365) label14 = tkinter.Label(text="=" + str(a9),font=(10),bg=w) label14.place(x=245,y=365) label15 = tkinter.Label(text="=" + str(a10),font=(10),bg=w) label15.place(x=45,y=405) label16 = tkinter.Label(text="=" + str(a11),font=(10),bg=w) label16.place(x=145,y=405) label17 = tkinter.Label(text="=" + str(a12),font=(10),bg=w) label17.place(x=245,y=405) label18 = tkinter.Label(text="=" + str(a13),font=(10),bg=w) label18.place(x=45,y=445) label19 = tkinter.Label(text="=" + str(a14),font=(10),bg=w) label19.place(x=145,y=445) label20 = tkinter.Label(text="=" + str(a15),font=(10),bg=w) label20.place(x=245,y=445) label21 = tkinter.Label(text="=" + str(a16),font=(10),bg=w) label21.place(x=45,y=485) label22 = tkinter.Label(text="=" + str(a17),font=(10),bg=w) label22.place(x=145,y=485) label23 = tkinter.Label(text="=" + str(a18),font=(10),bg=w) label23.place(x=245,y=485) label24 = tkinter.Label(text="=" + str(a19),font=(10),bg=w) label24.place(x=45,y=525) label25 = tkinter.Label(text="=" + str(a20),font=(10),bg=w) label25.place(x=145,y=525) label26 = tkinter.Label(text="=" + str(a21),font=(10),bg=w) label26.place(x=245,y=525) label27 = tkinter.Label(text="=" + str(a22),font=(10),bg=w) label27.place(x=45,y=565) label28 = tkinter.Label(text="=" + str(a23),font=(10),bg=w) label28.place(x=145,y=565) label29 = tkinter.Label(text="=" + str(a24),font=(10),bg=w) label29.place(x=245,y=565) square(canvas) score_pack() def canvas_delete_all(): canvas.delete("all") main_tree() def main_two(): global score canvas.create_rectangle(0,0,1540,1540,fill = "black") score = 0 root.after(3000,canvas_delete_all) def main_two_sub(): global index,list_move,score,label2,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24 label2.place_forget() score = 0 score_pack() index -= 1 list_move = [25,25,25,25,25,25,25,25,25,25,25,25, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0, 25,25,25,25,25,25,25,25,25,25,25,25] a1 = 6 a2 = 6 a3 = 6 a4 = 6 a5 = 6 a6 = 6 a7 = 6 a8 = 6 a9 = 6 a10 = 6 a11 = 6 a12 = 6 a13 = 6 a14 = 6 a15 = 6 a16 = 6 a17 = 6 a18 = 6 a19 = 6 a20 = 6 a21 = 6 a22 = 6 a23 = 6 a24 = 6 if __name__ == "__main__":main_two() score = 0 def score_pack(): global label4 label4.place_forget() label4 = tkinter.Label(text = "SCORE=" + str(score),font = ("systm",50)) label4.place(x=10,y=170) def main_tree(): global x3, y3,label3,label4 label3 = tkinter.Label(text = "LEVEL1",font = ("system",70)) label3.place(x=10,y=10) label4 = tkinter.Label(text = "SCORE=" + str(score),font = ("systm",50)) label4.place(x=10,y=170) canvas.create_rectangle(470,100,470+600,100+600,fill="#E6E6FA",width=0) canvas.create_rectangle(420,50,470,750,fill="#006400",width=0) canvas.create_rectangle(420,50,1120,100,fill="#006400",width=0) canvas.create_rectangle(1070,50,1120,750,fill="#006400",width=0) canvas.create_rectangle(420,700,1120,750,fill="#006400",width=0) for i in range(13): y = i * 50 + 100 canvas.create_line(470,y,1070,y,fill="black") x = i * 50 + 470 canvas.create_line(x,100,x,700,fill="black") (x3,y3) = 1200,200 now_square(canvas) canvas.create_rectangle(10,280,300,600,fill="white") canvas.create_rectangle(20,290,40,310,fill="red") canvas.create_rectangle(120,290,140,310,fill="blue") canvas.create_rectangle(220,290,240,310,fill="gold") canvas.create_rectangle(20,330,40,350,fill="limegreen") canvas.create_rectangle(120,330,140,350,fill="deeppink") canvas.create_rectangle(220,330,240,350,fill="purple") canvas.create_rectangle(20,370,40,390,fill="cyan") canvas.create_rectangle(120,370,140,390,fill="orange") canvas.create_rectangle(220,370,240,390,fill="ivory") canvas.create_rectangle(20,410,40,430,fill="navy") canvas.create_rectangle(120,410,140,430,fill="violet") canvas.create_rectangle(220,410,240,430,fill="indianred") canvas.create_rectangle(20,450,40,470,fill="gainsboro") canvas.create_rectangle(120,450,140,470,fill="mistyrose") canvas.create_rectangle(220,450,240,470,fill="skyblue") canvas.create_rectangle(20,490,40,510,fill="khaki") canvas.create_rectangle(120,490,140,510,fill="coral") canvas.create_rectangle(220,490,240,510,fill="greenyellow") canvas.create_rectangle(20,530,40,550,fill="tan") canvas.create_rectangle(120,530,140,550,fill="snow") canvas.create_rectangle(220,530,240,550,fill="maroon") canvas.create_rectangle(20,570,40,590,fill="olive") canvas.create_rectangle(120,570,140,590,fill="crimson") canvas.create_rectangle(220,570,240,590,fill="green") color_determine() canvas.bind("<1>",block_move) if __name__ == "__main__" : main_one() root.bind("<Key>",key_down) root.mainloop()
退会済みユーザー

退会済みユーザー

2020/07/23 07:52

ちょっと待ってください! これだと、どこがインデントされているのかわかりません!!!!! githubというものを使ったことがあるならそちらに貼り付けてリンクを教えてください!
akisan55

2020/07/23 08:55

PCのスペックはNECのノートパソコン 型番は「NM150/M」です。 githubに初めてアップしました。 これでいいか分かりませんが… https://github.com/akisan55/Python.git 同じ色を隣り合わせにしてはいけないゲームとして作りました。 宜しくお願いします。
退会済みユーザー

退会済みユーザー

2020/07/24 00:26

遅くなりました。有難うございます。見てみたところ、スペック問題ではなさそうですね。 これ、よく見ると、変数を沢山使っていて見づらいので一度修正かけますね。
akisan55

2020/07/24 00:40 編集

有難うございます。 宜しくお願いします。 勉強させていただきます。
退会済みユーザー

退会済みユーザー

2020/07/24 03:27 編集

修正かけました。tkinterはオブジェクト指向のシステム(オブジェクト指向とは簡単に言うとwhileループとかで毎回確認せずにボタンを押したらこの関数が実行されると指定して実行するwhileループを使わずにやるプログラミング方法です。)なのでglobalを使うのは自分は吐き気がしてくるのでclassで実行されるように変更しました。 他にもa1やa2などのlistなどでまとめられるものがありましたのでまとめました。(今回は番号が飛んてしまったりしてその部分の修正をかけるのが面倒なので辞書型というものを使用しています。) 修正後のプログラムをpull requestしました。ファイルはこちらです。 https://github.com/akisan55/Python/pull/1/files 重い原因はこれから探します...
teamikl

2020/07/24 04:42

重い原因は、ある程度プレイを重ねた後の GC 等が考えられますね。 Score を300位稼いでからウィンドウを閉じようとすると、再現出来ました。 解消法は、tkinter.Label の引数に name= を指定して見て下さい。 Labelウィジェットが毎回、新規生成されるのを抑制できます。
teamikl

2020/07/24 11:43

問題と関係ないけど、気付いた点報告しておきます。 0,0,0,0,0,0,0,0,0,0,0,0, 左右の終端 がないので 左端と上の列の右端が隣扱いになってます。
akisan55

2020/07/24 12:30

有難うございます。 確かにIndexErrorが出ていました。(関係があるのでしょうか?) 0,0,0,0,0,0,0,0,0,0,0,0,の左右の終端がないとはどういうことですか? すいません。理解ができません。 どのようにすればよいのですか?お願いします。
teamikl

2020/07/24 21:28 編集

IndexError は別問題です。 ---- まずは、どうして 25~という値が置かれているのか、 理解するところから始めましょう。 例えば、左端のマス目をクリックした時、それ以上左のチェックは不要ですよね? ですが、端かどうかをチェックしていると、上下左右について4つチェックが必要 12x12(144) 中 10x10(100) の大半のマス目は端ではないので、 端かどうかを確認するのは冗長な作業で、コードが煩雑になります。 そこで、予め 14x14 の範囲に対して枠を含めた 16x16 の範囲を用意して データ(0~24)には現れない値を、枠を表すデータとして入れておきます。 これにより端かどうかを確認する必要なく、 上下左右との色を確認するだけでよくなり、コードが簡潔になります。 上下の枠に関しては現状のコードでこれはできています。(GAMEOVERかどうかをチェックする部分) なので左右も対応しましょう。 - list_move データに左右の枠を追加する、(合計 14x14) 25,~の行は 左右の枠分2つ 25 を増やします 25,0,0,0,(略),0,0,0,25, 各行に対して。  25 で 0 を囲むような形になるはずです。 - GAMEOVERのチェックも、リストのサイズ変化に合わせて修正が必要 縦チェックの 12 -> 14 の 2か所 詳しくは「番兵」で検索して見て下さい。 パズルプログラミングでは良く使われるテクニックです。
guest

回答4

0

k += 1 を追加してもやはり数字が表示されません。

何処に追加されたのだろう?伝わらなかったかもしれないので回答に投稿します

イメージ説明
145行目付近

python

1 k = 6 2 for i in range(285, 605, 40): 3 for j in range(45, 345, 100): 4 self.label_[k].place(x=j, y=i) 5 k += 1

投稿2020/07/24 11:28

teamikl

総合スコア8664

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

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

0

ウィジェットの使い方ですが、関数内で毎回新規ウィジェットを作成されてるので、
初回起動時に一度のみ作成し、必要に応じ表示・非表示やテキスト変更と使うようにして見て下さい。

大量のオブジェクト生成によるパフォーマンス低下は有りえます。
この場合、何度もプレイすると発現します。


確認方法:

# block_move_sub関数内で print(label2)

一例ですが、ゲームを2度程プレイすると

.!label419 .!label1801

実際の表示、数値の部分は、どれだけ長く続けられたかにより異なります。

この名前は連番で作成される為に、1800個ものウィジェットが作成されてることになります。
→タスクマネージャ等から、長時間プレイ時のメモリの増加を見て見ましょう。

(といっても、相当数プレイしないとパフォーマンスに影響するには至りませんが。)

解決策:

  • Label を何度も作らず、生成済みのウィジェットを再利用する
  • 生成時に固定のname引数を付ける事で、再生成を抑制する
  • ウィジェットは作らず、キャンバスに直接 create_text で描画する

途中プログラムが応答するまで時間がかかりすぎます。

after で、3秒~5秒待ってる部分ではないでしょうか?
それともウィンドウを閉じようとする時?

他にある場合、再現手順を具体的に書いてみてください。

例えば、スコアを 20, 6, 66, 77, 40 で5回プレイした後に
ウィンドウを閉じようとした時、応答に時間が掛かる、等。
(※ 補足追記: 例として挙げただけで、実際に試して重たくなったわけではありません)

スコアは適当ですが、何回クリックしたか→
関数が呼ばれる回数 → ウィジェットが生成される数を、大雑把に把握する為の目安です。

クリック数の方がより詳細な情報なので、デバッグ情報として
関数を呼び出した回数等を数えログに表示したりすると、より正確に状況が把握できます。


上記に書いた問題は、一応起こりえる問題なのですが、
実際にパフォーマンスに影響するまでやるとすると相当な時間が掛かります。

テストの為にプログラム内で無駄に関数を呼んだりして、
耐久テストをしないと、手作業のデバッグでの再現は難しい。

意図的に起こすとしたら以下のような感じです。

python

1import tkinter as tk 2 3root = tk.Tk() 4for _ in range(20000): 5 label = tk.Label(root) 6 label.place(x=0, y=0) 7 label.place_forget() 8else: 9 print(label) 10tk.Button(root, text="destroy", command=root.destroy).pack() 11tk.Button(root, text="quit", command=root.quit).pack() 12root.mainloop()

quit ではメインループの終了フラグを立てるだけなので直ぐに終了できますが、
ウィンドウの閉じるアイコンや、destroy ボタンでは、
ウィジェットを全て破棄しようとする為、ウィジェットの数に応じた時間が掛かります。

20000 の部分の数を減らすと、destroy でも直ぐに終了できるようになるので、
ウィジェットの数がパフォーマンスに影響する事があるのは解ると思います。

追記2: 終了時ではなく、プレイ中にパフォーマンス低下するとしたら、
大量のオブジェクトを生成した時のGCの影響が考えられます。


追記: ウィジェット生成時の name 引数について

python

1label = tk.Label(root, name="a")

とすると、上のコードでウィジェット数は 20002 -> 3 になります。
(同じnameを付ける事で、再生成を抑制)
代わりにクラス初期化時の速度は遅くなるので、起動が遅く感じますが。
一度に大量に生成しないなら、許容範囲位には収まるはずです。

投稿2020/07/23 23:34

編集2020/07/24 04:27
teamikl

総合スコア8664

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

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

0

コード、マシンスペック、環境によると思いますが、以下では重く感じません。

Python

1import tkinter as tk 2import numpy as np 3import random 4 5def add_rect(x, y): 6 tag = str(len(rs)+1) 7 rgb = [random.randint(0,255) for _ in range(3)] 8 fill = f'#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}' 9 canvas.create_rectangle(x, y, x+50, y+50, fill=fill, tag=tag) 10 rs.append(tag) 11 12def on_click(e): 13 add_rect(e.x, e.y) 14 15random.seed(110) 16rs = [] 17root = tk.Tk() 18canvas = tk.Canvas(root, width=1024, height=768) 19canvas.pack() 20canvas.bind("<Button-1>", on_click) 21 22for _ in range(144): 23 add_rect( random.randint(10,1000), random.randint(10,700)) 24 25root.mainloop()

追記

マシンスペックは問題ないと思います。コードで気になるところは.afterを使っているところです。
.after(の第一引数を全部1など小さい数値にしてみてください。
こちらの環境ではそれでとくに重く感じませんでした。

投稿2020/07/23 04:00

編集2020/07/23 09:39
can110

総合スコア38266

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

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

0

ベストアンサー

理由がわかりました。

理由1

line_profilerというものを使用して一行一行の実行時間がわかるものです。詳しくは次の解説サイトを見てください。
https://www.yoheim.net/blog.php?q=20171005
以下のサイトを見ている前提で話します。(みにくくなるため)
https://github.com/kumitatepazuru/teratail/blob/master/7-24/time
まず、何回か出てきているTotal timeです。
これはその下の関数がどのくらい時間がかかっているかを表示しています。
そのように見てみるとcolor_determineがおもいみたいです。もっと見てみるとtimeの欄の部分が異常に高い行があるのがわかると思うのですが、それがこの行です。
self.label_[i] = tkinter.Label(self.root, text="=" + str(self.a[i - 6]), font=(None, 10), bg=w)
tkinter自体は重くないのですが、tkinterオブジェクトを作るのは強烈に重いです。
なので、そんなプログラムを600回強も動かすとそりゃ重くなります。

理由2

また、これ以外に限らずゲームでもお馴染みオブジェクト数が多すぎると重くなります(どのライブラリでもこれは言える)
なので、少しでも軽くするためには、タイルの部分を画像にしてやってみる、変数の作り過ぎに気をつけるなどの方法があります。

追記1


このように自分のパソコンでは表示されます。

投稿2020/07/24 04:42

編集2020/07/24 08:16
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

akisan55

2020/07/24 05:17

有難うございます。 修正後のプログラムを張り付けて実行してみましたが、 「self.label_[i] = tkinter.Label(self.root, text="=" + str(self.a[i - 6]), font=(None, 10), bg=w)」が重いせいか、左に色をカウントするラベルが表示されません。 引数nameを追加してみましたが、結果は同じでした。 ラベルを表示する解消法・対処法はありませんか?お願いします。
teamikl

2020/07/24 06:13

ウィジェット生成自体はそれ程重たくありませんよ。 他の処理に比べては相対的に時間はかかってるので、改良の余地はありますが。 → 毎回全部の要素を再描画するのではなく、変化のある部分のみにする、等。 表示されないのは別問題です。 その少し下に ラベルのplace() を読んでいる処理があると思いますが、 添字が固定されてるので、簡単な修正方法は k += 1 を追加 k = 6 ~~とある2重のforループの内部 self.label_[k].place(x=j, y=i) の後に k += 1
退会済みユーザー

退会済みユーザー

2020/07/24 08:13 編集

また、tkinterは非同期処理というものでやっているので(ここからは本当かわからない憶測ですが) Labelを作成 ↓ 表示 ↓ tkinterがすぐに消す(擬似的に)(画面の再描画等のラグで) ということが起きているのではないでしょうか。
退会済みユーザー

退会済みユーザー

2020/07/24 08:18

理由2にも書きましたが、タイルの部分を画像にしてやってみるとオブジェクト数が2*タイル数減らせる計算(多分)なのでやってみたらどうでしょうか。
akisan55

2020/07/24 10:59

有難うございます。 重くなってしまうのは解消されました。 追記1の部分ですが、タイルの部分を画像にしても、k += 1 を追加してもやはり数字が表示されません。 なぜか、それぞれの色が6つ以上出てくるようにもなりました。(各色6つを上限にしていました。) classで実行したことはあまりないので、教えていただけませんか?
退会済みユーザー

退会済みユーザー

2020/07/24 11:01

速攻で作ったものなのでちょっとバグがあったみたいです。直してみます(明日になると思う)
退会済みユーザー

退会済みユーザー

2020/07/24 11:02

あと、質問事項は解決されたみたいなので一旦解決済みにしてください。(一応ここでのコメントは可能です。)
teamikl

2020/07/24 11:36

重くなった原因が曖昧なままな気がします。 オブジェクトの作り過ぎが原因なのには同意ですが、 タイルは毎回破棄されてるので、一定数以上増えません。 勿論、効率化にはなりますが、ラベルのウィジェットが無制限に増え続ける問題を対策しないと、 「重くなる問題」の根本的な解消にはならないです。 ---- > tkinterは非同期処理というものでやっている どの部分を指してるのか文脈によりますが、勝手に非同期になったりはしません。 ラベル表示が消えてるのは ひとつしか place() が呼ばれていないからです。
akisan55

2020/07/24 12:14

本当に有難うございます。 とても勉強になりました。 今後に生かして、頑張っていきます。
退会済みユーザー

退会済みユーザー

2020/07/25 10:01

返信遅れてしまい申し訳ありません。自分もこの頃tkinterに触っていないものですから、うろ覚えで理由がわかりませんでした...すみません。また何かあって教えてほしいことなどありましたら、teratailまたは以下のissueに送ってもらえると答えられます。宜しくおねがいします。 https://github.com/kumitatepazuru/teratail/issues
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問