Я занимаюсь разработкой приложения на Python с использованием Qt для Python (PySide2). Я компетентный Java-разработчик среднего уровня, однако Python и GUI для меня в основном новы.
Графический интерфейс пользователя состоит из одного главного окна с рядом значков (кнопок) внутри QScrollArea, который прокручивает влево и вправо по центру экрана, когда пользователь меняет свой выбор с помощью клавиатуры или джойстика. Это упрощенная версия интерфейса Sony XMB . Я включаю только горизонтальное меню, а не дополнительное вертикальное меню, и пока оно работает довольно хорошо. Однако теперь я хотел бы улучшить производительность анимации меню, внедрив выделенную очередь анимации FIFO, но каждый подход, который я пробовал до сих пор, приводил меня к препятствиям.
Основная проблема заключается в том, что делать, когда пользователь перемещается влево или вправо два или более раз подряд, чтобы предыдущая анимация не была завершена до запуска следующей. Наилучший подход, который я нашел до сих пор, заключается в том, чтобы по существу игнорировать события изменения выбора, пока анимация еще выполняется, но это может заставить интерфейс пользователя чувствовать себя немного безразличным.
Я собрал базовый пример ниже с более медленной анимацией, чтобы было проще воспроизвести эффект игнорируемых нажатий клавиш.
import sys
from PySide2 import QtWidgets
from PySide2.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QPushButton, QHBoxLayout, QSizePolicy, \
QSpacerItem, QApplication
from PySide2.QtCore import Qt, QSize, QPropertyAnimation, QPointF, Slot
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.title = "Test"
self.init_ui()
def init_ui(self):
self.setWindowTitle(self.title)
self.setGeometry(400, 400, 1600, 900)
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.parent = QVBoxLayout()
self.tool_parent = QHBoxLayout()
self.exit_button = QPushButton("Exit")
self.exit_button.setFixedSize(QSize(60, 60))
self.exit_button.clicked.connect(self.on_quit)
self.tool_parent.addWidget(self.exit_button)
self.tool_parent.addSpacerItem(QSpacerItem(40, 40, QSizePolicy.Expanding, QSizePolicy.Minimum))
self.parent.addLayout(self.tool_parent)
self.parent.addSpacerItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))
self.widget.setLayout(self.parent)
self.animation = QPropertyAnimation(self.exit_button, b'pos')
self.animation.setDuration(300)
self.show()
def keyPressEvent(self, event):
if event.key() == Qt.Key_L:
self.shift_left()
elif event.key() == Qt.Key_R:
self.shift_right()
elif event.key() == Qt.Key_Escape:
self.on_quit()
def shift_left(self):
# Only shift left if there's space on the screen and
# no animations are currently running
if self.exit_button.geometry().topLeft().x() > (self.exit_button.width()) and self.animation.state() == 0:
end = QPointF(self.exit_button.geometry().topLeft().x() - 100, self.exit_button.geometry().topLeft().y())
self.animation.setEndValue(end)
self.animation.start()
def shift_right(self):
# Only shift right if there's space on the screen and
# no animations are currently running
if self.exit_button.geometry().topRight().x() < (1600 - self.exit_button.width()) and self.animation.state() == 0:
end = QPointF(self.exit_button.geometry().topLeft().x() + 100, self.exit_button.geometry().topLeft().y())
self.animation.setEndValue(end)
self.animation.start()
def on_quit(self):
QtWidgets.qApp.exit(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
Нажатие клавиш «L» или «R» сместит кнопку влево или вправо на экране, используя анимацию, но любой ввод во время работы анимации игнорируется. Это поведение, которое я хотел бы улучшить, внедрив очередь анимации, которая удовлетворяет следующим требованиям:
- Пользовательский интерфейс продолжает принимать входные данные во время работы анимации
- Анимации не перекрываются, все они запускаются последовательно
Я пробовал несколько способов, в том числе:
- Помещение анимации в очередь, которую отдельный рабочий поток опрашивает и обрабатывает, однако отдельные потоки не могут изменять элементы пользовательского интерфейса с помощью QT, поэтому это не работает.
- Использование QSequentialAnimationGroup, но они не предназначены и не безопасны для повторного использования и добавления при запуске анимации.
- Ввод цикла while () сразу после запуска анимации, чтобы дождаться его завершения, но это блокирует пользовательский интерфейс во время ожидания.
На данный момент у меня в основном нет идей, поэтому мы будем благодарны за любые советы.