Как обрабатывать события колеса QComboBox с помощью фильтра событий? ⇐ Python
-
Anonymous
Как обрабатывать события колеса QComboBox с помощью фильтра событий?
В Qt6 многие виджеты (QComboBox, QSpinBox) крадут события колесика мыши, которые должны обрабатываться их родительским виджетом (например, QScrollArea), даже если у них нет фокуса и даже когда focusPolicy< /code> установлено значение StrongFocus.
Я могу подклассифицировать эти классы виджетов и переопределить обработчик wheelEvent, чтобы игнорировать эти события и выполнить то, что я хочу, но делать это таким образом кажется неэлегантным, потому что мне нужно создать подкласс каждого класса виджета который демонстрирует такое поведение.
класс MyComboBox(QtWidgets.QComboBox): defwheelEvent(self, event: QtGui.QWheelEvent) -> Нет: если не self.hasFocus(): событие.игнорировать() еще: супер().wheelEvent(событие) Qt предлагает другой способ игнорировать события с помощью installEventFilter, который кажется гораздо более масштабируемым и элегантным, поскольку я могу создать один фильтр событий и применить его к любому количеству различных виджетов.
class WheelEventFilter(QtCore.QObject): """Игнорирует события колеса, когда виджет еще не находится в фокусе.""" def eventFilter(self, смотрел: QtCore.QObject, событие: QtCore.QEvent) -> bool: если ( isinstance(просматривалось, QtWidgets.QWidget) и не смотрел.hasFocus() и event.type() == QtCore.QEvent.Type.Wheel ): # Это фильтрует событие, но также останавливает его # от распространения до родительского виджета. вернуть истину # На самом деле это не игнорирует событие для данного виджета. событие.игнорировать() вернуть ложь еще: вернуть super().eventFilter(просмотренное, событие) Однако моя проблема в том, что этот фильтр событий не фильтрует события так, как я ожидал. Я ожидаю, что он отфильтрует событие только для просматриваемого объекта, а также позволит передать событие родительскому виджету для обработки, но этого не происходит. .
Можно ли добиться того же эффекта, что и обработчик wheelEvent, определенный выше, с помощью eventFilter?
Вот автономный воспроизводимый пример, демонстрирующий такое поведение. Если вы попытаетесь прокрутить область прокрутки, наведя указатель мыши на одно из полей со списком, поле со списком украдет фокус и событие колеса.
импортировать систему из PySide6 импортировать QtWidgets, QtCore класс MyWidget(QtWidgets.QWidget): def __init__(self) -> Нет: супер().__init__() # # макет self._layout = QtWidgets.QVBoxLayout() self.setLayout(self._layout) # макет виджета self._mainwidget = QtWidgets.QWidget() self._mainlayout = QtWidgets.QVBoxLayout() self._mainwidget.setLayout(self._mainlayout) # виджеты для виджета self._widgets = {} число_виджетов = 20 для меня в диапазоне (num_widgets): комбо = QtWidgets.QComboBox() combo.addItems([str(x) для x в диапазоне(1, 11)]) комбо.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) self._mainlayout.addWidget(комбо) self._widgets = комбо # область прокрутки self._scrollarea = QtWidgets.QScrollArea(self) self._scrollarea.setWidgetResizable(True) self._scrollarea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) self._scrollarea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) self._layout.addWidget(self._scrollarea) # виджет для области прокрутки self._scrollarea.setWidget(self._mainwidget) def main() -> Нет: приложение = QtWidgets.QApplication(sys.argv) виджет = МойВиджет() виджет.шоу() приложение.exec() если __name__ == "__main__": основной()
В Qt6 многие виджеты (QComboBox, QSpinBox) крадут события колесика мыши, которые должны обрабатываться их родительским виджетом (например, QScrollArea), даже если у них нет фокуса и даже когда focusPolicy< /code> установлено значение StrongFocus.
Я могу подклассифицировать эти классы виджетов и переопределить обработчик wheelEvent, чтобы игнорировать эти события и выполнить то, что я хочу, но делать это таким образом кажется неэлегантным, потому что мне нужно создать подкласс каждого класса виджета который демонстрирует такое поведение.
класс MyComboBox(QtWidgets.QComboBox): defwheelEvent(self, event: QtGui.QWheelEvent) -> Нет: если не self.hasFocus(): событие.игнорировать() еще: супер().wheelEvent(событие) Qt предлагает другой способ игнорировать события с помощью installEventFilter, который кажется гораздо более масштабируемым и элегантным, поскольку я могу создать один фильтр событий и применить его к любому количеству различных виджетов.
class WheelEventFilter(QtCore.QObject): """Игнорирует события колеса, когда виджет еще не находится в фокусе.""" def eventFilter(self, смотрел: QtCore.QObject, событие: QtCore.QEvent) -> bool: если ( isinstance(просматривалось, QtWidgets.QWidget) и не смотрел.hasFocus() и event.type() == QtCore.QEvent.Type.Wheel ): # Это фильтрует событие, но также останавливает его # от распространения до родительского виджета. вернуть истину # На самом деле это не игнорирует событие для данного виджета. событие.игнорировать() вернуть ложь еще: вернуть super().eventFilter(просмотренное, событие) Однако моя проблема в том, что этот фильтр событий не фильтрует события так, как я ожидал. Я ожидаю, что он отфильтрует событие только для просматриваемого объекта, а также позволит передать событие родительскому виджету для обработки, но этого не происходит. .
Можно ли добиться того же эффекта, что и обработчик wheelEvent, определенный выше, с помощью eventFilter?
Вот автономный воспроизводимый пример, демонстрирующий такое поведение. Если вы попытаетесь прокрутить область прокрутки, наведя указатель мыши на одно из полей со списком, поле со списком украдет фокус и событие колеса.
импортировать систему из PySide6 импортировать QtWidgets, QtCore класс MyWidget(QtWidgets.QWidget): def __init__(self) -> Нет: супер().__init__() # # макет self._layout = QtWidgets.QVBoxLayout() self.setLayout(self._layout) # макет виджета self._mainwidget = QtWidgets.QWidget() self._mainlayout = QtWidgets.QVBoxLayout() self._mainwidget.setLayout(self._mainlayout) # виджеты для виджета self._widgets = {} число_виджетов = 20 для меня в диапазоне (num_widgets): комбо = QtWidgets.QComboBox() combo.addItems([str(x) для x в диапазоне(1, 11)]) комбо.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) self._mainlayout.addWidget(комбо) self._widgets = комбо # область прокрутки self._scrollarea = QtWidgets.QScrollArea(self) self._scrollarea.setWidgetResizable(True) self._scrollarea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) self._scrollarea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) self._layout.addWidget(self._scrollarea) # виджет для области прокрутки self._scrollarea.setWidget(self._mainwidget) def main() -> Нет: приложение = QtWidgets.QApplication(sys.argv) виджет = МойВиджет() виджет.шоу() приложение.exec() если __name__ == "__main__": основной()
Мобильная версия