Как заставить tkinter ждать завершения нового потока? - PullRequest
1 голос
/ 06 мая 2019

Как выполнить tkinter в функции fix() подождать, пока label's текст не будет изменен, а затем напечатать end.

Текущая работа: когда я нажимаю кнопку sub, создается новый потоки for цикл выполняется.После 10000000 циклов мой ярлык изменится на 9999999.Но до того, как моя метка изменилась, tkinter печатает end.

Я пробовал t.join(), но графический интерфейс замораживается.

import tkinter as tk
from tkinter import ttk
import threading

root = tk.Tk()
label = tk.Label(text='vinoth')
label.pack()

def fix():
    a=0
    t = threading.Thread(target=count, args=(a,))
    t.start()
    #t.join()
    print('end')

def count(a):
        for i in range(0,10000000):
            a=i
        label['text'] = a

button = tk.Button(text='sub', command=fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()

root.mainloop()

Ответы [ 2 ]

2 голосов
/ 06 мая 2019

Вы должны быть осторожны с многопоточностью tkinter приложений, потому что интерфейс к tcl / tk не поддерживает его. Это означает, что только основной поток может совершать вызовы tkinter и его виджетам.

Тем не менее, вы можете обойти ограничение, используя универсальный метод after(), чтобы запланировать периодическое выполнение функции и связь с потоком, либо с помощью потоково-безопасных механизмов, таких как Queue или через глобальные переменные в сочетании с `Lock ' для управления одновременным доступом к нему или к ним.

Вот пример использования последнего для выполнения того, что вы пытаетесь выполнить:

import tkinter as tk
from tkinter import ttk
import threading


POLLING_DELAY = 250  # ms
lock = threading.Lock()  # Lock for shared resources.
finished = False

root = tk.Tk()
label = tk.Label(text='vinoth')
label.pack()

def fix():
    global finished

    with lock:
        finished = False
    t = threading.Thread(target=count)
    t.daemon = True
    root.after(POLLING_DELAY, check_status)  # Start polling.
    t.start()

def check_status():
    with lock:
        if not finished:
            root.after(POLLING_DELAY, check_status)  # Keep polling.
        else:
            print('end')

def count():
    global finished

    for i in range(10000000):
        a = i
    with lock:
        finished = True
        label['text'] = a


button = tk.Button(text='sub', command=fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()

root.mainloop()
1 голос
/ 07 мая 2019

Я попробовал использовать функцию root.update() в цикле while. Не уверен, что это прямо сейчас делать вещи! Но отправка кода в любом случае:

import tkinter as tk
from tkinter import ttk
import threading

root = tk.Tk()

class test():

    def __init__(self):
        self.label = tk.Label(text='vicks')
        self.label.pack()
        button = tk.Button(text='sub', command=self.fix)
        button.pack()
        dropdown = ttk.Combobox()
        dropdown.pack()

    def fix(self):
        self.finished = False
        t = threading.Thread(target=self.count)
        t.daemon = True
        t.start()
        self.check_status()
        print('end')

    def check_status(self):
        while self.finished is False:  #keeps running until the variable finished becomes True
            root.update()

    def count(self):
        a=0
        for i in range(100000000):
            a = i
        self.label['text'] = a
        self.finished = True

c = test()

root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...