Как я могу избежать замораживания Tkinter GUI в Python3? - PullRequest
1 голос
/ 04 апреля 2020

Я новичок в python и создал приложение Tkinter, которое будет выполнять все файлы python, существующие в каталоге, при нажатии кнопки запуска. У моего GUI также есть индикатор выполнения, чтобы увидеть текущий прогресс.

, поэтому вот мой код

import os
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox

directory = dir_path = os.path.dirname(os.path.realpath(__file__))

files = os.listdir(directory)


root = Tk()
root.geometry('200x200')
root.maxsize(200,200)
root.minsize(200,200)
root.title('PYTOEXE')

v = 0
def begin():
    global v
    for x in files:
        os.system('pyinstaller '+x)
        v=v+1
        p['value']=v


p = Progressbar(root,length=200,max=len(files))

b = Button(root,text="Start",command=lambda: begin())



p.place(x=0,y=0)
b.place(x=62,y=30)

root.mainloop()

, но моя проблема в том, что всякий раз, когда я нажимаю кнопку запуска, GUI зависает и коды начинают компилироваться, и когда они завершаются, GUI размораживается, и индикатор выполнения сразу заполняется ...

Поэтому я хочу, чтобы GUI не зависал во время обработки и отображал правильный прогресс на панели прогресса.

Пример кода и пояснения будут для меня лучше.

Спасибо за ваше драгоценное время ...

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

Это сработало. Не нужно использовать .after() для проверки завершения потока.

import os
from tkinter import *
from tkinter.ttk import *
import threading

def use_pyinstaller(): # this function is to execute pyinstaller command and add value to progressbar.
    v = 0
    for x in files:
        os.system('pyinstaller '+x)
        v+=1
        p['value'] = v

def begin():
    threading.Thread(target=use_pyinstaller).start() # create a non-block thread to start the function.

directory = dir_path = os.path.dirname(os.path.realpath(__file__))
files = os.listdir(directory)
root = Tk()
root.geometry('200x200')
root.maxsize(200,200)
root.minsize(200,200)
root.title('PYTOEXE')

p = Progressbar(root,length=200,max=len(files))
b = Button(root,text="Start",command=begin)

p.place(x=0,y=0)
b.place(x=62,y=30)

root.mainloop()
0 голосов
/ 04 апреля 2020

Прежде всего, аргумент command для кнопки может быть просто: command=begin.

GUI наборы инструментов, такие как tkinter, управляются событиями . Они зависят от плавного потока событий клавиатуры и мыши для правильной работы. Обратные вызовы (например, command от кнопки) называются от событием l oop (root.mainloop). Поэтому обратный вызов должен занять короткое время (скажем, 50 мс), чтобы не заморозить GUI. Поэтому вы никогда не должны запускать длительный l oop в обратном вызове. Вы должны программировать в другом стиле .

Приведенная выше ссылка приводит вас к статье на моем веб-сайте, где я сравниваю простую программу командной строки с эквивалентной GUI программой. Хотя эта программа не использует внешние процессы, она иллюстрирует принцип.

Правильный способ сделать это в GUI, это запустить multiprocessing.Process из обратного вызова кнопки. Затем используйте метод root.after, чтобы периодически запускать обратный вызов, который проверяет, завершен ли Process, и затем запускать новый процесс.

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