Можете ли вы убить приложение Tk из другого потока? Если нет, то можно ли легко отправить логическое сообщение в основной поток? - PullRequest
0 голосов
/ 16 января 2020

Я писал приложение Tk (мое первое), и, как вы можете сказать, я новичок в python. Мне нужен был поток, чтобы не блокировать основной поток, в котором работает экземпляр Tk, поэтому я загружаю файл в другом потоке. Вот мой код:

from tkinter import Toplevel, FLAT, BOTH, X, IntVar, StringVar, HORIZONTAL, Text, END, Tk, LEFT, RIGHT
from tkinter.ttk import Label, Frame, Style, Button, Checkbutton, Progressbar, Entry
import tkinter.messagebox as messagebox
import os
import sys
import threading
from shutil import copyfile, rmtree
class DownloadWindow:
    def __init__(self, root):
        self.root = root

        self.master = Toplevel(self.root)
        self.master.protocol('WM_DELETE_WINDOW', self.close)
        self.master.geometry("600x400")
        self.master.resizable(False, False)
        frame = Frame(self.master, relief=FLAT)
        frame.pack(padx=10, pady=5, fill=BOTH)
        self.mode = 'unksize'
        self.progressbar = Progressbar(frame, orient=HORIZONTAL, length=100, mode='indeterminate')
        self.progressbar.pack(fill=X)
        self.progressbar.start(20)
        self.downloaded = 0
        self.progressv = Text(frame, bd=0, insertborderwidth=0, state='disabled', background='#f0f0ed', font=('Segoe UI', 10))
        self.progressv.pack(fill=BOTH, pady=(10,5))
        self.downloading = threading.Thread(target=self.download)
        self.downloading.start()
    def download_progress(self, count, block_size, total_size):
        if total_size != -1 and self.mode != 'ksize':
            self.mode = 'ksize'
            self.progressbar.stop()
            self.progressbar.configure(mode='determinate', maximum=total_size)
        elif total_size == -1 and self.mode != 'unksize':
            self.mode = 'unksize'
            self.progressbar.configure(mode='indeterminate')
        if self.mode == 'ksize':
            self.downloaded += block_size
            self.progressbar.step(block_size)
            if self.downloaded == total_size:
                self.progress('Download ended.')

    def download(self):
        self.pathres = False
        self.progress('Downloading...', False)
        # Let's suppose this failed
        messagebox.showerror(title='uh oh this failed', message='Download failed, error bla bla bla')
        self.error_close()
        self.progressbar.stop()
        self.finish()
    def finish(self):
        self.progress('The installation is finished...')
    def progress(self, what, lb=True):
        self.progressv.configure(state='normal')
        self.progressv.insert(END, ('\r\n' if lb else '')+what)
        self.progressv.configure(state='disabled')
    def error_close(self):
        # This is technically the method that's called when the download fails with an error
        # This closes the window, but not the console itself... You can check that in taskmanager or from console if running from it...
        self.root.destroy()
    def close(self):
        pass
if __name__ == "__main__":
    root = Tk()
    DownloadWindow(root)
    root.withdraw()
    root.mainloop()

^ Пример выполнения
Проблема: как выйти из приложения на части, когда я обнаружил ошибку? В основном я пытался самостоятельно. root .destroy (), но, как вы можете сказать, он не работал (он закрывал окно, но mainl oop продолжал работать), пытался sys.exit (), он не работал ни (Я думаю, что это убило новый поток вместо «основного»), и я передал root Tk () также другому потоку, но он тоже не сработал.
Вы можете запустить приведенный выше пример чтобы понять больше.

Я поместил печать сразу после метода root .mainl oop и однажды поток вызвал root .destroy, как ни странно, он напечатал строку выхода ... Итак, я понятия не имею, как решить эту проблему

1 Ответ

0 голосов
/ 16 января 2020

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

import tkinter as tk
from threading import Thread


root = tk.Tk()


def threaded_window():
    top = tk.Toplevel(root)
    tk.Button(top, text='kill main application in main thread', command=root.destroy).pack()


tk.Button(root, text='Open threaded window', command=lambda: Thread(target=threaded_window).start()).pack()
root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...