Задать вопрос
  • Как асинхронно использовать gui и несколько бесконечных циклов?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Асинхронный код запустить в отдельном потоке, а все взаимодействия с интерфейсом из этого кода делать сигналами. Есть ещё библиотеки, позволяющие использовать цикл событий asyncio в качестве цикла событий окна, что звучит здорово, но сам я их в бою не пробовал.

    UPDATE:
    Надо же, с 2019-го многое поменялось в интересную сторону. Для PyQt и PySide есть qasync, который активно развивается, а для Tk вообще не нужны сторонние библиотеки:
    import tkinter as tk
    from tkinter import ttk
    import asyncio
    
    
    class App:
        async def exec(self):
            self.window = Window(asyncio.get_event_loop())
            await self.window.show();
    
    
    class Window(tk.Tk):
        def __init__(self, loop):
            self.loop = loop
            self.root = tk.Tk()
            self.animation = "░▒▒▒▒▒"
            self.label = tk.Label(text="")
            self.label.grid(row=0, columnspan=2, padx=(8, 8), pady=(16, 0))
            self.progressbar = ttk.Progressbar(length=280)
            self.progressbar.grid(row=1, columnspan=2, padx=(8, 8), pady=(16, 0))
            button_block = tk.Button(text="Calculate Sync", width=10, command=self.calculate_sync)
            button_block.grid(row=2, column=0, sticky=tk.W, padx=8, pady=8)
            button_non_block = tk.Button(text="Calculate Async", width=10, command=lambda: self.loop.create_task(self.calculate_async()))
            button_non_block.grid(row=2, column=1, sticky=tk.W, padx=8, pady=8)
    
        async def show(self):
            while True:
                self.label["text"] = self.animation
                self.animation = self.animation[1:] + self.animation[0]
                self.root.update()
                await asyncio.sleep(.1)
    
        def calculate_sync(self):
            max = 3000000
            for i in range(1, max):
                self.progressbar["value"] = i / max * 100
    
        async def calculate_async(self):
            max = 3000000
            for i in range(1, max):
                self.progressbar["value"] = i / max * 100
                if i % 1000 == 0:
                    await asyncio.sleep(0)
    
    
    asyncio.run(App().exec())
    Ответ написан
    Комментировать