В ответ на несколько комментариев, вот новая версия кода:
import tkinter as tk
from tkinter import ttk, END, NW, GROOVE
import threading
import queue
import time
from pickle import FALSE
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.msgCt=0
self.thrdCt=0;
self.scaleVal=tk.DoubleVar()
self.doneSignal=tk.BooleanVar()
self.doneSignal.set(False)
self.doneSignal.trace("w",self.on_doneSignal_set)
self.progressbar = ttk.Progressbar(self, orient='horizontal',
length=300,
maximum=100.0,
variable=self.scaleVal)
self.scaleVal.set(0.0)
self.startBtn = tk.Button(self, text="Start", command=self.spawnthread)
self.stopBtn=tk.Button(self,text="Stop", command=self.stopthread)
self.stopBtn.config(state="disabled")
self.msgBtn = tk.Button(self,text="Set Msg", command=self.sendMessage)
self.msgTxt=tk.StringVar(self,"Messages Here...")
self.msgBox=tk.Message(self,textvariable=self.msgTxt,width=200,
anchor=NW,relief=GROOVE)
self.msgBox.grid(row=0,column=0,columnspan=3)
self.progressbar.grid(row=1,column=0,columnspan=3)
self.startBtn.grid(row=2,column=0)
self.stopBtn.grid(row=2,column=1)
self.msgBtn.grid(row=2,column=2)
def on_doneSignal_set(self,*kwargs):
self.sendMessage("Thread is DONE")
self.startBtn.config(state="active")
self.stopBtn.config(state="disabled")
def stopthread(self):
if self.thread.is_alive():
self.thread.stopNow()
def spawnthread(self):
self.thrdCt=0
self.startBtn.config(state="disabled")
self.stopBtn.config(state="active")
self.thread = ThreadedClient(self.msgTxt,self.scaleVal,self.doneSignal)
self.thread.start()
# self.periodiccall()
def sendMessage(self,msg=None):
if not msg==None:
self.msgTxt.set(msg)
else:
self.msgTxt.set("Message {}".format(self.msgCt))
self.msgCt+=1
class ThreadedClient(threading.Thread):
def __init__(self, mtxt,dvar,dsig):
threading.Thread.__init__(self)
self.msgTxt=mtxt
self.scaleVal=dvar
self._stopNow=False
self._doneSignal=dsig
self._lock=threading.Lock()
def run(self):
self._stopNow=False
self.scaleVal.set(0.0)
for x in range(1, 10):
if not self.checkStopNow():
time.sleep(2)
msg = "Function %s finished..." % x
self.msgTxt.set(msg)
self.scaleVal.set(x*10)
else:
break
self._doneSignal.set(True)
def stopNow(self):
with self._lock:
self._stopNow=True
def checkStopNow(self):
rtrn=False
with self._lock:
rtrn=self._stopNow
return rtrn
if __name__ == "__main__":
app = App()
app.mainloop()
Во-первых, мотивация для этого упражнения в первую очередь: у меня есть большое приложение python, которое использует Scipy.optimize, чтобы найти решение проблемы моделирования. Это часто может занять много времени, поэтому я хотел, чтобы он работал, но периодически публиковать сообщения пользователю, чтобы они знали, что происходит, позволяли пользователю прервать работу посередине и, наконец, отправлять сообщение на главную Поток, что моделирование сейчас сделано. Мой исходный код был частично основан на примере потоков, который предполагал модель потоков производителя / потребителя, при которой производитель создает данные (помещенные в очередь), а потребитель их потребляет. Это неправильная модель для моей проблемы, поэтому у этого нового кода нет очереди. Он просто моделирует длительный процесс моделирования с использованием метода run (), в котором есть вызовы sleep (), которые, очевидно, могут быть заменены шагами в вызовах функции SciPy.minimize.
В этом новом примере DoubleVar используется для позволяют потоку обновлять progressBar (спасибо stovfl за это предложение), StringVar обновляет окно сообщения в главном потоке из потока моделирования и, наконец, BooleanVar, чтобы сигнализировать основному потоку, что все сделано. Эта версия не имеет опроса в основной теме. Мне это не кажется очень изящным решением!
Как я узнаю, что изменения в DoubleVar, StringVar и BooleanVar проходят в основной поток? Только то, что эта программа работает !! Обратите внимание, что окно сообщения может быть обновлено либо из потока моделирования, либо с помощью кнопки в главном потоке GUI.
Опять же, комментарии приветствуются. Укажите причины, по которым это НЕ должно работать, а затем скажите, почему оно делает с учетом этих причин! Это нарушает какой-то базовый c дизайн Python, или возникнет ситуация, когда по какой-то причине это не сработает ??