简体   繁体   English

在tkinter中使用Queue(线程,Python 3)

[英]Using Queue with tkinter (threading, Python 3)

I have a script in Python 3 and I'm trying to make a GUI for it using tkinter. 我在Python 3中有一个脚本,我正在尝试使用tkinter为其创建GUI。

Here is a complete example of working code: 这是工作代码的完整示例:

#!/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()

You can run it and see the working window. 您可以运行它并查看工作窗口。

I'm quite new to tkinter, so I have several questions and will be gratefull for any help. 我是tkinter的新手,所以我有几个问题,将不胜感激。 Thanks. 谢谢。

The idea of this GUI - is that there are 3 buttons - start running, stop running, and clear text window. 此GUI的想法-有3个按钮-开始运行,停止运行和清除文本窗口。 Text window - should be a substitute for a console - all messages should be printed in text window, instead of console. 文本窗口-应该替代控制台-所有消息都应在文本窗口而不是控制台中打印。

For now I'm using queue to print messages. 现在,我正在使用队列来打印消息。 But I guess I'm using it in a wrong way - because I need manually to check the queue every time after I put something there. 但是我想我使用的方式有误-因为每次在其中放置东西后,我都需要手动检查队列。

So, QUESTIONS: 因此,问题:

1) Is there a way to check queue autamatically ALL THE TIME - and instantly print to text window everything which gets to the queue, no matter from which thread it came there? 1)有没有一种方法可以一直自动检查队列-并将进入队列的所有内容立即打印到文本窗口,无论它来自哪个线程? (I can put up with checking queue every time after I put something there, but there will be couple of functions where it is impossible to predict how many times they will send something to queue - so I will not be able to check queue for unknown number of times.) (我在每次放置东西之后都可以忍受每次检查队列,但是会有几个函数无法预测他们将多少东西发送到队列中-因此我将无法检查队列中的未知对象次数。)


I will consider the question answered if you answer the FIRST question. 如果您回答第一个问题,我将考虑回答的问题。 Other questions are optional. 其他问题是可选的。 Thank you. 谢谢。

2) Am I starting the GUI correctly? 2)我可以正确启动GUI吗? Should it be in the init () or somewhere else? 应该在init ()还是其他地方?

3) how to hide the console window? 3)如何隐藏控制台窗口? (tried renaming to .pyw - neither console, nor GUI showed up. Tried putting self.root.withdraw() after self.root = Tk() - the result: console showed up, GUI - not.) (尝试重命名为.pyw-控制台和GUI均未显示。尝试将self.root.withdraw()放在self.root = Tk()之后-结果:控制台显示,GUI-未显示。)

4) Is there any clumsy or stupid places in this code (GUI, threading, queue)? 4)此代码中是否有笨拙或愚蠢的地方(GUI,线程,队列)? As I told - I'm new to tkinter and wrote this code by several manuals - so I could misunderstand some or all of them and do it in a wrong way. 正如我所说的-我是tkinter的新手,并由几本手册编写了此代码-因此我可能会误解其中的一部分或全部,并且以错误的方式进行。

Thanks in advance for your help. 在此先感谢您的帮助。

It figured out to be quite simple: in this function 它看起来很简单:在此函数中

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)

should be added one more call to itself - even after successfull printing. 应该再增加一个调用-即使在成功打印之后。 After this - I can send text to queue from anywhere and it will be printed without calling this function right after sending text to queue. 此后-我可以从任何地方发送文本到队列,并且在将文本发送到队列后无需调用此函数就可以打印文本。

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)
            self.root.after(100, self.listen_for_result)
        except queue.Empty:
            self.root.after(100, self.listen_for_result)

So now 所以现在

self.thread_queue.put('Getting files\n')

can be used in any thread. 可以在任何线程中使用。 Instead of 代替

 self.thread_queue.put('Getting files\n')
 self.root.after(100, self.listen_for_result)

double lines like before. 像以前一样双线。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM