我正在使用python 2.7并使用Tkinter构建了一个UI。我正在使用线程和队列来在主脚本工作时保持UI响应。基本摘要是脚本读取文本文件,解析其中的一些信息并将该信息放入字典中的字典和列表中,然后使用该信息发送TCP modbus请求(使用pyModbus)。然后它将响应/结果写入文本文件。结果还会打印出UI中包含的Text小部件。 Text小部件的更新由mainloop处理。
对于线程和队列我还是比较新的,我在解决这个问题时遇到了麻烦。
我遇到的问题是我需要在列表中的每个项目循环后包含~10ms的睡眠,以便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)
答案 0 :(得分:0)
找到了一种让UI主要响应的方法。如上面的评论中所述,队列正在接收快速的功能,该功能将持续工作,导致UI锁定。我做了它所以它将打印最多5条消息,然后休息1分钟并回忆起允许UI“赶上”的功能。消息的打印速度几乎与它们一样快。
如果移动或调整大小,UI将略微无响应。在运行时,我没有与其他UI元素交互的问题。
如果你不介意它慢,你也可以将while循环更改为if语句。我运行的一个过程从14秒开始,使用if语句下降到大约5或6秒,使用下面的代码。如果您将pullCount
break
点更改为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)