Python线程的tkinter GUI没有响应,除非使用睡眠时间。

2024-10-04 01:27:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用的是python2.7,并使用Tkinter构建了一个UI。我使用线程和队列在主脚本工作时保持UI的响应。基本概要是脚本读取一个文本文件,解析出其中的一些信息,并将该信息放入字典和字典中的列表中,然后使用该信息发送TCP modbus请求(使用pyModbus)。然后将响应/结果写入文本文件。结果还可以通过UI中包含的文本小部件打印出来。文本小部件的更新由mainloop处理。你知道吗

我对线程和队列还是相当陌生的,我很难理解这个问题。你知道吗


我遇到的问题是,我需要在列表中的每一项循环后加入~10毫秒的睡眠时间,以便UI保持响应。如果我包括了睡眠时间,它会按预期工作,如果没有,它会冻结直到线程进程完成,然后一次更新UI(如果不使用线程的话)。10毫秒的睡眠时间可以稍微短一点。再多的量也行。你知道吗

下面是处理更新日志的代码:

textQueue = Queue.Queue()

def TextDisplay(message, disTime="false", myColor="black", bgColor="white"):
    textQueue.put([message, disTime, myColor, bgColor])

class LogUI:
    def __init__(self, master):
        self.master = master

        '''other ui elements, not relevent'''

        self.mainLogFrame = Frame(self.master)
        self.mainLogFrame.pack(side="top", fill="both", expand="yes", padx=5, pady=2)

        self.logText = Text(self.mainLogFrame, height=2)
        self.logText.pack(side="left", fill="both", expand="yes", padx=5, pady=2)

        self.ThreadSafeTextDisplay()

    def ThreadSafeTextDisplay(self):
        while not textQueue.empty():
            tempText = textQueue.get(0)
            message = tempText[0]
            disTime = tempText[1]
            myColor = tempText[2]
            bgColor =  tempText[3]

            message = str(message) + "\n"

            '''bunch of formating stuff'''

            logUI.logText.insert(END, message)
            print message
            #NOTE: tried to include a sleep time here, no effect

        self.logText.after(10, self.ThreadSafeTextDisplay)

下面是当用户单击按钮时调用的非线程函数。你知道吗

def ParseInputFile():
    '''non-threaded function, called when user clicks button'''
    inputList = []

    inputFile = mainUI.fullInFileEntry.get()
    with open(inputFile, 'r') as myInput:
        '''open file and put contents in list'''
        for line in myInput:
            inputList.append(line.strip())

    outFile = mainUI.outFileEntry.get().strip() + '.txt'

    i = 1
    tableBol = False
    inputDict = {}
    inputKeys = []
    tableID = None
    for item in inputList:
        '''parses out inputKeys, inputDict using regular expressions'''

    runInputGetQueue.put([inputKeys, inputDict, outFile, inputFile])

以下是接收解析信息并处理modbus请求的线程函数(注意:我尝试注释实际的modbus请求,没有效果):

def RunInputThread():
    time.sleep(.1)
    while 1:
        while not runInputGetQueue.empty():
            tempGet = runInputGetQueue.get(0)
            inputKeys = tempGet[0]
            inputDict = tempGet[1]
            outFile = tempGet[2]
            inputFile = tempGet[3]

            outFile = open(outFile, 'w')

            TextDisplay('< Start of %s input file > ' % inputFile, True, 'blue')

            for key in inputKeys:
                '''loops through the keys in the dictionary'''
                TextDisplay(key) #just used as an example.
                for lineIndex in range(len(inputDict[key]['tableLines'])):
                    '''lots of code that loops thorugh the lines of input file, frequently calls the TextDisplay() function'''
                    TextDisplay(inputDict[key][lineIndex]) #just used as an example.

                    time.sleep(0.01) #UI will become unresponseive if not included. 



            outFile.close()
        time.sleep(0.001)

Tags: inself信息uimessagedef线程outfile
1条回答
网友
1楼 · 发布于 2024-10-04 01:27:35

找到了一种让用户界面更具响应性的方法。如上面的评论所述,队列正在接收一些东西,以使函数持续工作,从而导致UI锁定。我这样做,它将打印最多5条消息之前,采取了1毫秒的休息和召回的功能,使用户界面'赶上'。消息打印几乎一样快,因为他们进来。你知道吗

如果移动UI或调整其大小,UI将稍微没有响应。我没有问题与其他UI元素互动,而这是运行。你知道吗

如果您不介意while循环太慢,也可以将它改为if语句。我运行的一个进程从使用if语句的14秒降到使用下面的代码的5或6秒。这与将pullCountbreak点改为1而不是5是一样的。你知道吗

def ThreadSafeTextDisplay(self):
    pullCount = 0
    while not textQueue.empty():
        pullCount += 1
        tempText = textQueue.get(0)
        message = tempText[0]
        disTime = tempText[1]
        myColor = tempText[2]
        bgColor =  tempText[3]

        message = str(message) + "\n"

        '''bunch of formatting stuff'''

        logUI.logText.insert(END, message)
        print message
        if pullCount >= 5: break  #you can change the 5 value to whatever you want, the higher the number the faster stuff will print but the UI will start to become unresponsive. 
    self.logText.after(1, self.ThreadSafeTextDisplay)

相关问题 更多 >