首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程运行时TkInter禁用按钮

线程运行时TkInter禁用按钮
EN

Stack Overflow用户
提问于 2019-07-09 19:18:23
回答 1查看 950关注 0票数 2

我有一个应用程序,当一个按钮被按下时,它会尝试生成文本。大多数情况下,文本生成速度很快,但有一个函数需要大约20秒才能执行(取决于文本量)。在这个过程中,GUI经常冻结,所以我在一个单独的线程上调用了这个函数,这个字段上的一切都很好。

现在我有了一个按钮的问题。当花费一些时间执行的函数正在运行时,用户仍然可以单击该按钮,并且该函数将被执行多次,同时第一个调用仍在处理中。我想通过在该函数运行时禁用所有按钮来防止这种情况,但我无法使线程正常工作。

下面是我的代码:

代码语言:javascript
复制
def generate_text():
    choice = dropdown_choice.get()
    if context_obj.context_text.get() == '':
        if choice == 'OpenAI':
            context = 'Some random context text'

        else:
            context = ' '
    else:
        context = context_obj.context_text.get()

    if choice == 'OpenAI':
        progress.start(50)
        progress_bar_text = Label(text='Please wait while the text is being generated',
                            background='#E5F2FF',
                            font=("Helvetica", 12))

        progress_bar_text.place(relx=.2, 
                            rely=.66, 
                            anchor="c")

         # multithreading for the OpenAI text generation
        q = queue.Queue()
        thread1 = Thread(target=openAI_generator.sample, args=[text_amount.get(), temperature.get(), context, q])
        thread1.start()

        def display_AI_text(q):
            openAI_text = q.get()
            generated_text.configure(state='normal')
            generated_text.delete(1.0,END)
            generated_text.insert(tk.END, openAI_text)
            generated_text.configure(state='disabled')

            progress.stop()
            progress_bar_text.place_forget()

        thread2 = Thread(target=display_AI_text, args=[q])
        thread2.start()

在这段代码中,thread1执行函数,thread2从该函数获取输入并显示它。

我想要做的是,当thread2正在执行时,所有的按钮都被禁用,当线程结束时,这些按钮再次变为启用状态。

我尝试添加以下内容:

代码语言:javascript
复制
thread2 = Thread(target=display_AI_text, args=[q])
generate_button.config(state="disabled")
thread2.start()

然后:

代码语言:javascript
复制
thread2.join()
generate_button.config(state="normal")

但是这段代码冻结了应用程序。我假设主线程正在等待thread2完成,这就是它没有响应的原因。

有谁知道解决这个问题的方法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-09 21:21:52

在许多GUI中,您不能在线程中更改GUI-您必须在主进程中进行更改。

您可以使用队列将信息发送到主进程,主进程将更新GUI。

在Tkinter中,您可以使用

代码语言:javascript
复制
root.after(time_in_milliseconds, function_name) 

定期运行检查来自该队列的消息的函数。

或者它可以定期检查

代码语言:javascript
复制
thread2.is_alive()

而不是使用thread2.join(),因为is_alive()不会阻塞代码。

代码语言:javascript
复制
import tkinter as tk
from threading import Thread
import time

def long_running_function():
    print('start sleep')
    time.sleep(3)
    print('end sleep')

def start_thread():
    global t
    global counter

    b['state'] = 'disable'
    counter = 0

    t = Thread(target=long_running_function)
    t.start()

    check_thread()
    # or check after 100ms
    # root.after(100, check_thread) 

def check_thread():
    global counter

    if not t.is_alive():
        b['state'] = 'normal'
        l['text'] = ''
    else:
        l['text'] = str(counter)
        counter += 0.1

        # check again after 100ms
        root.after(100, check_thread) 

#-----------------------------------------------------

# counter displayed when thread is running        
counter = 0

root = tk.Tk()

l = tk.Label(root)
l.pack()

b = tk.Button(root, text="Start", command=start_thread)
b.pack()

root.mainloop()
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56951383

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档