PyQt6, как обновить 96 виджетов одновременно как можно быстрее?Python

Программы на Python
Anonymous
PyQt6, как обновить 96 виджетов одновременно как можно быстрее?

Сообщение Anonymous »


Речь идет о моем приложении с графическим интерфейсом.


Изображение


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

Окно разделено на 9 областей, каждая из которых используется для изменения стиля группы связанных виджетов. Предварительный просмотр виджетов находится слева в каждой области, справа от каждой области находится область прокрутки, содержащая виджеты, которые меняют определенный аспект стиля.

Доступными параметрами настройки или атрибутами стилей виджетов, которые можно изменить, являются border-style, border-color, text-color и цвет фона, если виджет использует плоский фон, в противном случае — начальный цвет градиент и средний цвет градиента, если фон использует градиент. Градиент имеет три стопа, первый и последний стопы имеют один и тот же цвет.

Эти атрибуты можно изменить независимо для каждого состояния из всех возможных состояний, в которых может находиться виджет.

Существует два типа виджетов, меняющих стили. Один тип меняет цвет, другой меняет стиль границы. Стиль границы изменяется с помощью QComboBox, а цвета можно изменить с помощью QLineEdit и QColorDialog. Диалоговое окно вызывается нажатием соответствующей кнопки.

Каждая группа управляет ключом в словаре подчеркивания, в котором хранятся конфигурации стилей. При изменении состояния группы соответствующий ключ изменяется, стиль компилируется с использованием класса, а затем окно обновляется.
>
При нажатии кнопки «Пуск» ее текст изменится на «Стоп», а многие виджеты в области предварительного просмотра будут обновляться каждые 125 миллисекунд. А анимация для доски — это живая игра в крестики-нолики между двумя написанными мной ИИ. При нажатии кнопки паузы она становится кнопкой возобновления, а анимация приостанавливается. Нажимаем кнопку возобновления и анимация возобновляется. Нажимаю кнопку стоп и все останавливается и сбрасывается.

Нажатие кнопки рандомизации генерирует случайный стиль, все 96 групп, которые меняют стиль, обновляются одновременно, и стиль применяется следующим образом:


Изображение



Изображение



Изображение


Это работает, проблема в том, что обновление всех этих виджетов одновременно приводит к зависаниям, окно перестает отвечать на несколько секунд, а затем окно обновляется. Я хочу устранить отставание.

Из-за размера приложения я не буду публиковать здесь полный код. Кроме того, поскольку проблема возникает при одновременном обновлении 96 виджетов, я не буду приводить минимальный воспроизводимый пример. Приложение не завершено и не работает должным образом, поэтому я пока не могу опубликовать его в Code Review, на самом деле оно почти завершено, и я опубликую его в Code Review, когда оно будет.

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

импортировать asyncio импортировать qasync импортировать случайный импортировать систему из concurrent.futures импортировать ThreadPoolExecutor класс ColorGetter(Box): экземпляры = [] def __init__(self, widget: str, key: str, name: str): супер().__init__() ColorGetter.instances.append(self) self.config = CONFIG[виджет], если виджет иначе CONFIG self.key = ключ self.name = имя self.set_color(self.config[ключ]) self.init_GUI() self.button.clicked.connect(self._show_color) self.picker.accepted.connect(self.pick_color) self.color_edit.returnPressed.connect(self.edit_color) защита init_GUI (сам): self.color_edit = ColorEdit(self.color_text) self.button = Кнопка(self.color_text) self.vbox = make_vbox(сам) self.vbox.addWidget(Label(self.name)) self.vbox.addWidget(self.color_edit) self.vbox.addWidget(self.button) self.picker = ColorPicker() def set_color(self, text: str): self.color = [int(text[a:b], 16) для a, b в ((1, 3), (3, 5), (5, 7))] @свойство защита color_text(сам): r, g, b = собственный цвет верните f"#{r:02x}{g:02x}{b:02x}" защита _show_color(self): self.picker.setCurrentColor(QColor(*self.color)) self.picker.show() защита _update(сам): self.button.setText(self.color_text) self.config[self.key] = self.color_text ГЛОБАЛЬНЫЕ["Окно"].update_style() защита Pick_color (сам): self.color = self.picker.currentColor().getRgb()[:3] self.color_edit.setText(self.color_text) self.color_edit.color = self.color_text self._update() защита edit_color (сам): текст = self.color_edit.text() self.color_edit.color = текст self.set_color(текст) self.color_edit.clearFocus() self._update() защита sync_config (сам): color_html = self.config[self.key] self.color = [int(color_html[a:b], 16) для a, b в ((1, 3), (3, 5), (5, 7))] self.color_edit.setText(color_html) self.color_edit.color = color_html self.button.setText(color_html) класс BorderStylizer(Box): экземпляры = [] def __init__(self, widget: str, key: str, name: str): супер().__init__() BorderStylizer.instances.append(self) self.config = CONFIG[виджет], если виджет иначе CONFIG self.key = ключ self.name = имя self.borderstyle = self.config[ключ] self.init_GUI() защита init_GUI (сам): self.vbox = make_vbox(сам) self.vbox.addWidget(Label(self.name)) self.combobox = ComboBox(BORDER_STYLES) self.vbox.addWidget(self.combobox) self.combobox.setCurrentText(self.borderstyle) self.combobox.currentTextChanged.connect(self._update) защита _update(сам): self.borderstyle = self.combobox.currentText() self.config[self.key] = self.borderstyle ГЛОБАЛЬНЫЕ["Окно"].update_style() защита sync_config (сам): self.borderstyle = self.config[self.key] self.combobox.setCurrentText(self.borderstyle) асинхронная защита sync_config(): цикл = asyncio.get_event_loop() с ThreadPoolExecutor(max_workers=64) в качестве исполнителя: дождитесь asyncio.gather( *( цикл.run_in_executor(исполнитель, экземпляр.sync_config) например, в ColorGetter.instances + BorderStylizer.instances ) ) защита случайный_стиль(): для записи в CONFIG.values(): для k в записи: запись[к] = ( случайный.выбор(BORDER_STYLES) если k == "стиль границы" иначе f"#{random.randrange(16777216):06x}" ) asyncio.run(sync_config()) ГЛОБАЛЬНЫЕ["Окно"].update_style() ГЛОБАЛЬНЫЕ["Окно"].qthread.change.emit() если __name__ == "__main__": приложение = QApplication(sys.argv) app.setStyle("Fusion") если sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) цикл = qasync.QEventLoop (приложение) asyncio.set_event_loop(цикл) Я пытался устранить задержку, запустив обновление асинхронно, но получилось не очень хорошо.

Какое решение лучше?

Вернуться в «Python»