Skip to content

21. (П10) Реалізація фонових задач без блокування інтерфейсу

Передумови

Мова в коді

Усі рядкові літерали, написи на кнопках, заголовок вікна, імена файлів та змінних — лише латиницею. Своє ім'я, прізвище та групу пишіть у транслітерації: Ivan Petrenko, KI-31. Кирилиця допускається тільки в коментарях.

Завдання

Написати два окремі файли з однаковим вікном і однаковою «довгою роботою» — циклом із паузами SLEEP_MS мілісекунд на кожному з STEP_COUNT кроків:

  1. blocking_task.py — робота виконується прямо в слоті кнопки;
  2. threaded_task.py — та сама робота винесена у воркер (QObject + moveToThread + QThread).

Мета практичної — побачити різницю власними руками: перше вікно на час роботи повністю замерзає, друге лишається живим.

Персоналізація

Константи оголошуються на початку кожного файлу:

STUDENT_NAME = "Ivan Petrenko"      # ваше ім'я та прізвище транслітерацією
STUDENT_GROUP = "KI-31"             # ваша група
APP_TITLE = "Task Demo"             # назва застосунку
STEP_COUNT = 10                     # скільки кроків у роботі
SLEEP_MS = 500                      # пауза на кожному кроці, мілісекунд

Заголовок вікна: Task Demo - Ivan Petrenko, KI-31.

Схема вікна

Вікно однакове в обох файлах:

+--------------------------------------------------+
|  QWidget          Task Demo - Ivan Petrenko, KI-31|
+--------------------------------------------------+
|  Ready                                            |
|   ^- status_label                                 |
|                                                   |
|  [#############-----------------------]           |
|   ^- progress_bar (0 .. STEP_COUNT)               |
|                                                   |
|  [        Start        ]                          |
|   ^- start_button                                 |
|                                                   |
|  [     Click me (0)    ]                          |
|   ^- click_button: лічильник клацань              |
+--------------------------------------------------+

Click me — це «датчик життя» вікна: він нічого не рахує, лише збільшує число у своєму написі.

Що має робити застосунок

Момент status_label progress_bar start_button
запуск Ready 0 доступна
під час роботи Working... росте на кожному кроці вимкнена
після роботи Done STEP_COUNT знову доступна

Файл 1: blocking_task.py

  • пауза робиться викликом time.sleep(SLEEP_MS / 1000) у слоті кнопки Start;
  • прогрес оновлюється на кожному кроці — progress_bar.setValue(step);
  • processEvents() використовувати заборонено.

Файл 2: threaded_task.py

  • клас Worker(QObject) із сигналами progress = Signal(int) та finished = Signal() і слотом run();
  • пауза робиться через QThread.currentThread().msleep(SLEEP_MS), а не time.sleep();
  • у Worker немає жодного віджета й жодного імпорту з PySide6.QtWidgets;
  • вікно створює QThread і Worker, викликає worker.moveToThread(thread), з'єднує thread.startedworker.run, а progress і finished — зі своїми слотами;
  • thread і worker зберігаються в полях вікна (self.thread, self.worker), а не в локальних змінних;
  • worker.finished з'єднано з thread.quit;
  • у closeEvent() вікно робить thread.quit() і thread.wait(3000), якщо потік ще працює.

Що перевірити руками

  1. Запустити blocking_task.py, натиснути Start і одразу клацати Click me — число не змінюється, вікно не перемальовується, прогрес стоїть на місці (або взагалі не малюється).
  2. Під час роботи blocking_task.py спробувати перетягнути вікно — воно не рухається; система може підписати заголовок Not Responding.
  3. Запустити threaded_task.py, натиснути Start і клацати Click me — число росте, прогрес рухається плавно, вікно перетягується.
  4. У threaded_task.py закрити вікно посеред роботи — застосунок завершується без повідомлення QThread: Destroyed while thread is still running.

Для звіту

Знімок екрана обох вікон одразу після натискання Start і кількох клацань Click me: у першому лічильник Click me (0), у другому — більший за нуль. Одним-двома реченнями пояснити, чому так.


Знайшли помилку чи бажаєте додати інформацію, щоб покращити курс? Створіть issue на GitHub