前提・実現したいこと
Tkinterでサイコロを振るアプリを作成しています。
ボタンを押すと乱数を生成し、それに対応したGIFが流れるというものです。
サイコロが転がり、目が決定するという、ループなしで1秒のGIFを6つ用意しています。
ボタンの上にあるEntryから回数を指定します (指定しない場合は1回) 。
GIFの表示にはOpenCVを使用しています。
発生している問題
等確率かどうかを調べるため、合計回数と平均をTkinterのウィンドウに表示しました。
そこで発生した、GIFの表示が終わるまで更新されない問題を解決するため、threadingを使用したのですが、1度実行するとOpenCVのウィンドウが閉じてしまいます。
該当のソースコード
Python
1import tkinter 2import cv2 3import random 4import threading 5 6rng_sum, qty = 0, 0 7fnt = ("Helvetica", 10) 8 9def animated_gif(): 10 rng = random.randint(1, 6) #乱数の生成 11 12 gif = cv2.VideoCapture("1~6/{}.gif".format(rng)) #GIFファイルの読み込み 13 fps = gif.get(cv2.CAP_PROP_FPS) 14 15 images = [] #画像をリストに追加 16 a = 0 17 while True: 18 is_success, img = gif.read() 19 if not is_success: 20 break 21 images.append(img) 22 a += 1 23 24 cv2.namedWindow("OpenCV", cv2.WINDOW_AUTOSIZE) #ウィンドウに表示 25 for b in range(len(images)): 26 cv2.imshow("OpenCV", images[b]) 27 cv2.waitKey(int(1000/fps)) 28 cv2.moveWindow('OpenCV', 100, 100) 29 30 global rng_sum, qty #平均を求める 31 rng_sum += rng 32 qty += 1 33 avg = rng_sum / qty 34 la1 = tkinter.Label(root, text = "total number of times: {}".format(qty), 35 fg = "white", bg = "green", font = fnt) 36 la1.place(x = 0, y = 45) #今は config() で更新しています 37 la2 = tkinter.Label(root, text = "average: {:.2f}".format(avg), 38 fg = "white", bg = "green", font = fnt) 39 la2.place(x = 0, y = 62) #同上 40 41def bu_on(): 42 thread1 = threading.Thread(target = work1) 43 thread1.start() 44 45def work1(): #回数の指定 46 c = en.get() 47 if c == "": 48 animated_gif() 49 else: 50 num = int(c) 51 for d in range(num): 52 animated_gif() 53 54root = tkinter.Tk() 55root.geometry("180x84") #サイズ 56root.geometry("+95+100") #位置 57root.attributes("-topmost", True) #最前面に表示 58root.configure(bg="green") 59en = tkinter.Entry(width = 30) 60en.pack() 61en.bind("<Return>", lambda event: bu_on()) 62bu = tkinter.Button(text = "Roll", width = 30, command = bu_on) 63bu.pack() 64root.mainloop() 65
試したこと
threadingにする前はウィンドウが閉じることはありませんでした。buのcommandをwork1にすると同じ状況になります。
※追記
同じ状況ではありませんでした。buのcommand、またはen.bindのlambdaをwork1にし、work1を1度でも実行すると、その後はbu_onを実行してもウィンドウが閉じることはありませんでした。根本的な解決には至っていないため、引き続き回答よろしくお願いします。
補足情報(FW/ツールのバージョンなど)
Python 3.10.2
初めてのアプリ作成なので見にくい部分もあると思いますが、よろしくお願いします。
追記
Python
1import tkinter 2import random 3 4root = tkinter.Tk() 5photo = tkinter.PhotoImage(file = "1~6/1.gif") 6gif_index = 0 7start_flag = False 8 9def times(t): 10 global start_flag 11 i = int(en.get() or 1) 12 if start_flag and t <= i: 13 roll() 14 root.after(1200, times, t + 1) 15 bu1.config(state = "disabled") 16 else: 17 bu1.config(state = "normal") 18 #なくてもいい? 19 start_flag = False 20 21def start(): 22 global start_flag 23 start_flag = True 24 times(1) 25 26def stop(): 27 global start_flag 28 start_flag = False 29 30def roll(): 31 global photo 32 rng = random.randint(1, 6) 33 photo = tkinter.PhotoImage(file="1~6/{}.gif".format(rng)) 34 #la["image"] = photo 35 la.config(image = photo) 36 gif() 37 38def gif(): 39 global gif_index 40 try: 41 photo.config(format="gif -index {}".format(gif_index)) 42 gif_index += 1 43 except tkinter.TclError: 44 gif_index = 0 45 else: 46 root.after(10, gif) 47 48 #print(gif_index, end = " ") 49 #if gif_index == 0: 50 # print("\n") 51 52la = tkinter.Label(root, image = photo) 53en = tkinter.Entry() 54bu1 = tkinter.Button(root, text = "Roll", command = start) 55bu2 = tkinter.Button(root, text = "Stop", command = stop) 56 57la.pack() 58en.pack() 59bu1.pack() 60bu2.pack() 61 62root.mainloop()

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/03/17 08:40
2022/03/17 11:01 編集
2022/03/19 07:35
2022/03/20 03:13
2022/03/20 07:44