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