我编写了一些代码,用于创建在更改json文件时(通过其他程序)更新的progressbars。这个想法是这个代码将与一个更大的项目结合起来,为用户提供有关json文件的信息。
我的问题:如果我激活其中一个进度条,则整个GUI会冻结。那个进度条工作得很好,但我不能启动其他任何一个。
我的计划:我已经阅读了tkinter和python,我相信我想要的是每个进度条在不同的线程上运行。我试过了;但它仍然冻结。 Quit按钮也无法正常工作。有什么建议?或者更简单的方法来解决这个问题?
这是我的代码(抱歉长度):
import threading
import time
from Tkinter import *
import json
import Queue
from time import sleep
master = Tk()
#somewhere accessible to both:
callback_queue = Queue.Queue()
#see (thread_working.py) for debugging help
######ProgressBar Code (my_progressbar.py)
class Meter(Frame):
#make a progress bar widget
def __init__(self, master, fillcolor = 'darkblue', text='', value=0.0, **kw):
Frame.__init__(self, master, bg='lightgray', width=350, height=20)
self.configure(**kw)
self._c = Canvas(self, bg=self['bg'], width=self['width'], height=self['height'], highlightthickness=0, relief='flat', bd=0)
self._c.pack(fill='x', expand=1)
self._r = self._c.create_rectangle(0,0,0, int(self['height']), fill=fillcolor, width=0)
self._t = self._c.create_text(int(self['width'])/2, int(self['height'])/2, text='')
self.set(value)
def set(self, value=0.0):
text = str(int(round(100 * value))) + ' %'
self._c.coords(self._r, 0, 0, int(self['width']) * value,int(self['height']))
self._c.itemconfigure(self._t, text=text)
self.update()
progbarlock = False # start with the prograssbar marked as not occupied
class guibuild:
def __init__(self):
guibuild.progbarlock = False
self.progbar = Meter(theframe) #makes the progressbar object
self.progbar.set(0.0) #sets the initial value to 0
self.progbar.pack(side=LEFT)
self.mybutton = Button(theframe, text="My Button", command = self.interval).pack(side = LEFT)
def stop_progbar(self):
self.progbar.stop()
def interval(self):
if guibuild.progbarlock == False:
counter = 0
#sleep(5) #slow down the loop
guibuild.progbarlock = True
i = float(0) #i is going to be the value set on the progressbar
while i <= 1.0: #will stop at 100%
the_file = open("sample.json")
data = json.load(the_file)
curr = data["curr_line"]
total = data["total_lines"]
if counter == total:
print "stop" #for debug purposes
self.stop_progbar
#pass
elif curr == counter:
#print "curr = counter" #debug
pass
elif curr == counter+1:
i += 1.0/total
#print i #debug
self.progbar.set(i) #apply the new value of i to the progressbar
print "the progressbar should reflect", str(int(round(i*100))) +"%progress right now"
print "the counter will increase"
counter += 1
#print counter #debug purposes
self.stop_progbar
#print "test"
else:
print "something is wrong - running.json is not available"
time.sleep(5)
guibuild.progbarlock = False
##########################################################################################################
def create_bar():
guibuild()
######Make the actual GUI
#master = Tk()
global theframe #makes the frame object global
theframe = Frame(master)
theframe.pack()
frame2 = Frame(master)
frame2.pack(side=BOTTOM)
quitbutton = Button(frame2, text="Quit", fg = "darkred", command = master.quit).pack(side=LEFT)
#original command was theframe.quit, original location was theframe (vs master)
##############Threading Stuff#####################
beginbutton = Button(theframe, text="Make Bar", command =create_bar).pack(side = BOTTOM)
def my_thread(func_to_call_from_main_thread):
callback_queue.put(guibuild)
#this must be here and below
def from_main_thread_nonblocking():
while True:
try:
callback = callback_queue.get(True) #doesn't block #was false
except Queue.Empty: #raised when queue is empty
break
callback()
#this allows for it to be activated several times
threading.Thread(target=guibuild).start()
while True:
master.mainloop()
master.destroy()
from_main_thread_nonblocking()
master.destroy()
sample.json看起来像这样:
{
"curr_line": 1,
"total_lines": 5
}
编辑:我修复了这个问题,但发现了一个新错误。一旦修复了bug,就会发布更正后的代码,以防有人来寻找答案并找到答案。
答案 0 :(得分:0)
我修复了所有错误,并希望为将来的搜索者分享这个答案。正如@BryanOakley所说,Tkinter不适用于线程。我研究了一些,并决定删除所有的while循环并使用Tkinter after()
方法。下面是我的代码的修改部分。
class guibuild:
def __init__(self):
self.master = master
guibuild.progbarlock = False
self.progbar = Meter(theframe) #makes the progressbar object
self.progbar.set(0.0) #sets the initial value to 0
self.progbar.pack(side=LEFT)
self.counter = 0
self.i = float(0) #i is the value set to the progressbar
self.mybutton = Button(theframe, text="My Button", command = self.interval).pack(side = LEFT)
def stop_progbar(self):
self.progbar.stop()
def interval(self):
if guibuild.progbarlock == False:
guibuild.progbarlock = True
the_file = open("sample_running.json")
data = json.load(the_file)
curr = data["curr_line"]
command = data["curr_line_text"]
total = data["total_lines"]
print self.counter
if self.i == 1.0:
self.stop_progbar
print "100% - process is done"
self.master.after_cancel(self.interval)
elif self.counter == total:
print "stop" #for debug purposes
self.i = 1.0
self.master.after(5000, self.interval)
elif curr == self.counter:
print self.counter
print self.i
self.master.after(5000, self.interval)
elif curr == self.counter+1:
self.i += 1.0/total
print self.i #debug
self.progbar.set(self.i) #apply the new value of i to the progressbar
print "the progressbar should reflect", str(int(round(self.i*100))) +"%progress right now"
print "the counter will increase"
self.counter += 1
print self.counter #debug purposes
self.stop_progbar
self.master.after(5000, self.interval)
else:
print "something is wrong - running.json is not available"
self.master.after(5000, self.interval)
guibuild.progbarlock = False
请注意,self.master.after()
的调用需要在每个if语句之后发生 - 这样self.master.after_cancel()
在调用时才会起作用。干杯!