当前位置: 首页 > 知识库问答 >
问题:

Tkinter冷冻线程?进步吧?

羊舌昆杰
2023-03-14

我编写了一些代码来创建progressbars,当json文件发生更改时(由另一个程序更改),progressbars会更新。这段代码将与一个更大的项目相结合,以便在编写json文件时向用户提供有关该文件的信息。

我的问题:如果我激活一个进度条,整个GUI就会冻结。那个进度条会正常工作,但我不能启动其他任何一个。

我的计划:我已经阅读了tkinter和python,我相信我想要的是每个进度条在不同的线程上操作。我试过了;但是仍然很冷。退出按钮也不能正常工作。有什么建议吗?或者更简单的方法来解决这个问题??

这是我的代码(抱歉长度):

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.html" target="_blank">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
}

编辑:我修复了这个问题,但发现了一个新的错误。一旦错误被修复,将发布更正后的代码,以防有人来寻找答案并找到它。

共有1个答案

姬成荫
2023-03-14

我修复了所有的bug,并想与未来的搜索者分享这个答案。正如@BryanOakley所说,Tkinter不能处理线程。我进一步研究了一些,决定删除所有while循环,并使用Tkinterafter()方法。下面是我代码的修改部分。

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()在被调用时工作。干杯!

 类似资料:
  • 按下按钮后,我的界面冻结。我使用线程,但我不知道为什么仍然挂起。任何帮助都将不胜感激。提前谢谢

  • 我有一个Python 3。x报表创建者,其I/O绑定(由于SQL而非python),在创建报表时主窗口将“锁定”数分钟。 所需要的只是在锁定GUI时使用标准窗口操作(移动、调整大小/最小化、关闭等)(GUI上的所有其他内容都可以保持“冻结”,直到所有报告完成)。 添加20181129:换句话说,tkinter必须只控制应用程序窗口的内容,并将所有标准(外部)窗口控件的处理留给O/S。如果我能做到这

  • 我是的新手,所以我试图为一个程序(我试图制作一个编译器)制作一个可执行文件,该程序使用一个setup.py脚本的模块: 我使用的是python 3.5,当我打开生成的向我抛出以下错误: 我怎样才能纠正这个错误?

  • 让冷光线在黑暗中发出微光。 用法 Your browser does not support the video tag. 案例:节能灯。 说明:当夜幕降临的时候,房子屋檐的灯就会亮起,为回家的人照明家的方向。当天色变亮的时候,灯就会自动关闭,节能省电。 所需模块:电源、蓝牙模块、光线传感器、冷光管驱动、冷光管、连接线10cm。

  • 我听说Python中的线程不容易处理,而且它们与tkinter的关系更加复杂。 我有以下问题。我有两个类,一个用于GUI,另一个用于无限进程。首先,我启动GUI类,然后启动无限进程类。我希望当您关闭GUI时,它也会完成无限过程,程序也会结束。 代码的简化版本如下: 单击关闭按钮(右上角)时,控制台中会出现以下错误: 我不知道为什么会这样,也不知道这意味着什么。

  • 我有一个带有“开始”按钮和进度条的小型GUI测试。期望的行为是: 单击开始 Progressbar振荡5秒 进度条停止 观察到的行为是“开始”按钮冻结5秒钟,然后显示进度条(无振荡)。 以下是我目前的代码: 根据Bryan Oakley提供的信息,我知道我需要使用线程。我试着创建一个线程,但我猜,由于线程是从主线程中开始的,所以没有帮助。 我的想法是将逻辑部分放在一个不同的类中,并从该类中实例化G