我在使用 Tkinter(和 ttk)和 Python 的 GUI 将我的代码组织成一个可用且不是超级错误的程序时遇到了麻烦。基本上,它现在只是从网上下载图像,但即使是简单的 GUI,我也遇到了麻烦。虽然一切都在控制台中工作,但制作 GUI 是一场噩梦,更不用说让它工作了。现在我已经让它工作了,但它经常崩溃,很明显我做错了,导致 GUI 中的变量错误没有被正确访问(即使是控制台中的错误消息,我自己也放了函数来确保事情正确运行)和不断的崩溃。
基本上我有这样的东西。
发生和需要工作的主要事情是:用户输入的字符串从 entrytext 发送到程序的密集部分(当前包含在一个线程中),密集部分步进 GUI 的进度条,密集部分发送文本消息到没有 GUI 和密集部分崩溃的文本框/记录器。此外,密集部分应该在 GUI 完全加载后立即开始,并在准备好时将启动消息发送到文本框。
密集部分处理其他事情,但不干扰 GUI,例如实际下载和保存图像、浏览和文件 I/O,而且我没有任何问题,反正大部分情况下。
我还阅读了有关队列和线程以及教程的内容,但我似乎还是没有得到它。尤其是我将如何让程序在 GUI 中不断步进进度条,同时向 GUI 发送文本消息(例如,我如何从队列中接近而不必执行非常缓慢且 CPU 密集型的 While 和 If 循环以及多个队列让它变得更加疯狂。在简单的示例中,只需有一个简单的 while 和 queue.get() 等待就很好了,因为它消耗的资源很少)。所以我的问题是,我需要为此实现什么样的结构,如果可能的话,我是否可以得到一两个示例(我从示例中学到的东西比从阅读文档中学习得更好)?非常感谢。
from Tkinter import *
import ttk
import Threading
import #a bunch of other stuff
class myHardWorkerThread (threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.setDaemon(True)
self.myClass = ModifiedConsoleClass()
def run(self):
#thread needs to wait at least a little otherwise the thread begins too
#fast and causes even more errors, probably due to it sending text to
#the textbox upon startup among other things and just overall no
#organization
time.sleep(3)
self.myClass.BeginDoingStuff()
class ApplyMyGuiAndStartThread():
def __init__(self, root, thread):
root.geometry('500x500')
root.resizable(0,0)
#Put backgrounds or images or logos here
self.canvas = Canvas(root)
self.canvas.pack()
#My textbox that acts like a Log/Console output
self.txtLogger = Text(root,state="disabled",wrap="word")
self.txtLogger.place()
self.scrollbar = Scrollbar(root)
self.scrollbar.place()
#Progressbar
self.myVal = IntVar()
self.TProgressbar = ttk.Progressbar(root, orient=HORIZONTAL, variable = self.myVal, mode='determinate')
self.TProgressbar.place()
#Entrybox for user input
self.txbEntryText = StringVar()
self.txtbEntry = ttk.Entry (root, textvariable=self.txbEntryText)
self.txtbEntry.place()
self.txtbEntry.bind("<Return>", self.SendFromGUItoThread)
self.thread = thread
self.thread.start()
def SendFromGUItoThread(self,arg=None):
myentry = str(self.txtbEntry.get())
self.txtbEntry.delete(0, END)
self.thread.myClass.entryBoxValueCopy = myentry
def SendFromThreadToGUI(self,msg):
try:
self.txtLogger['state'] = 'normal'
self.txtLogger.insert('end', msg)
self.txtLogger['state'] = 'disabled'
except:
print "Could not be printed"
class ModifiedConsoleCode():
def __init__(self):
#constants here like
self.entryBoxValueCopy = None
def BeginDoingStuff():
#Thread does the bulk of work here, includes connecting to websites,
#collecting info, sending text messages to GUI, downloading images and
#stepping the progressbar by a calculated amount by file size
def OneOfManyFunctionsUsedInsideBeginDoingStuff():
#Breaks things down like looping time.sleep waits for user input in the entry box
#showing up in entryBoxValueCopy, and using the user input to surf websites and
#collect images
if __name__ == '__main__':
root = Tk()
root.title(titleOfTheProgram)
worker = myHardWorkerThread()
w = ApplyMyGuiAndStartThread(root,worker)
root.mainloop()
os._exit(0)