【发布时间】:2018-07-29 10:54:54
【问题描述】:
我在 Python 3 中有一个脚本,我正在尝试使用 tkinter 为它制作一个 GUI。
这是一个完整的工作代码示例:
#!/usr/bin/python
# coding: utf-8
import pickle
import openpyxl
from tkinter import *
import threading
import queue
class Worker():
def __init__(self):
self.one_name_list = []
self.dic = {}
self.root = Tk()
self.root.title("GUI Python")
self.root.geometry("820x350")
self.thread_queue = queue.Queue()
self.btn1 = Button(text="start counting", width = '20', height = '1', background = "#555", foreground = "#ccc", command=self.start_working)
self.btn1.grid(row=0, column=0, columnspan=2, ipadx=10, ipady=6, padx=5, pady=5, sticky=N)
self.btn2 = Button(text="stop counting", width = '20', height = '1', background = "#555", foreground = "#ccc", command=self.stop_running)
self.btn2.grid(row=1, column=0, columnspan=2, ipadx=10, ipady=6, padx=5, pady=5, sticky=N)
self.btn5 = Button(text="clear window", width = '10', height = '1', background = "#555", foreground = "#ccc", command=self.tex_clear)
self.btn5.grid(row=3, column=0, columnspan=2, ipadx=10, ipady=6, padx=5, pady=5, sticky=N)
self.tex = Text(self.root, width = 72, height = 20, font="Verdana 10", wrap=WORD)
self.tex.grid(row=0, column=2, rowspan=4, ipadx=10, ipady=6, padx=5, pady=5)
self.S = Scrollbar(self.root, orient="vertical", command=self.tex.yview)
self.S.grid(row=0, column=4, rowspan=4, ipady=143, pady=5, sticky=W)
self.tex.config(yscrollcommand=self.S.set)
self.root.after(100, self.listen_for_result)
self.root.mainloop()
def read_from_pickle_file(self, filename):
""" Reads python object from pickle file. """
# with open(filename, 'rb') as handle:
# obj = pickle.load(handle)
self.thread_queue.put('Got list file.\n')
return True
def get_boxes(self, xlsx_filename, txt_filename=None):
pass # does some job
self.thread_queue.put('Got boxes list.\n')
def tex_clear(self):
self.tex.delete('1.0', END)
self.tex.see("end")
def stop_running(self):
pass # stops somehow\
def _print(self, text):
self.tex.insert(END, text)
self.tex.see("end")
def start_working(self):
t = threading.Thread(target=self.start_working_2)
t.start()
def start_working_2(self):
self.one_name_list = self.read_from_pickle_file('1.pickle')
self.root.after(100, self.listen_for_result)
self.boxes_list = self.get_boxes('1.xlsx')
self.root.after(100, self.listen_for_result)
self.thread_queue.put('Getting files\n')
self.root.after(100, self.listen_for_result)
def listen_for_result(self):
""" Check if there is something in the queue. """
try:
self.res = self.thread_queue.get(0)
self._print(self.res)
except queue.Empty:
self.root.after(100, self.listen_for_result)
if __name__ == '__main__':
se = Worker()
您可以运行它并查看工作窗口。
我有几个问题。
这个 GUI 的想法是有 3 个按钮 - 开始运行、停止运行和清除文本窗口。文本窗口 - 应该替代控制台 - 所有消息都应该在文本窗口中打印,而不是控制台。
现在我使用队列来打印消息。但我想我用错了——因为每次放东西后我都需要手动检查队列。
所以,问题:
-
有没有办法自动检查队列一直 - 并立即将进入队列的所有内容打印到文本窗口,无论它来自哪个线程? (每次放东西后,我都可以忍受检查队列,但是会有几个函数无法预测他们将发送东西多少次到队列中 - 所以我将无法检查队列是否未知次数。)
如果您回答第一个问题,我将考虑已回答的问题。
其他问题是可选的。 -
我是否正确启动了 GUI?应该在
__init__()还是其他地方? -
如何隐藏控制台窗口? (尝试重命名为 .pyw - 控制台和 GUI 均未出现。尝试将
self.root.withdraw()放在self.root = Tk()之后 - 结果:控制台出现,GUI - 未出现。) -
这段代码中是否有任何笨拙或愚蠢的地方(GUI、线程、队列)?我使用几本手册编写了这段代码,所以我可能会误解其中的部分或全部,并以错误的方式进行操作。
【问题讨论】:
-
请将该代码缩减为minimal reproducible example。此外,一个好的问题只问一件事,而不是一连串的事情。
-
布莱恩,谢谢。我缩短了代码并解释说只回答第一个问题就足够了。其他问题是可选的,尽管我也希望得到答案。 )
标签: python multithreading python-3.x tkinter queue