QSpinBox внутри QScrollArea: как предотвратить спин-бокс от кражи фокуса при прокрутке?
У меня есть элемент управления с несколькими объектами QSpinBox внутри QScrollArea. Все прекрасно работает при прокрутке в области прокрутки, если только мышь случайно не находится над одним из Qspin-полей. Затем QSpinBox крадет фокус,и события колеса манипулируют значением spin box вместо прокрутки области прокрутки.
Я не хочу полностью отключать использование колеса мыши для управления QSpinBox, но я хочу, чтобы это происходило только в том случае, если пользователь явно нажимает или вкладывает в QSpinBox. Является есть способ предотвратить кражу фокуса QSpinBox из QScrollArea?
Как сказано в комментарии к нижеприведенному ответу, установка Qt:: StrongFocus действительно предотвращает появление Focus rect на элементе управления, однако он по-прежнему крадет колесо мыши и регулирует значение в поле вращения и останавливает прокрутку QScrollArea. То же самое и с Qt::ClickFocus.
6 ответов:
Попробуйте удалить
Qt::WheelFocusиз спинбокса'QWidget::focusPolicy:spin->setFocusPolicy( Qt::StrongFocus );Кроме того, необходимо предотвратить попадание события колеса в спин-боксы. Это можно сделать с помощью фильтра событий:
explicit Widget( QWidget * parent=0 ) : QWidget( parent ) { // setup ... Q_FOREACH( QSpinBox * sp, findChildren<QSpinBox*>() ) { sp->installEventFilter( this ); sp->setFocusPolicy( Qt::StrongFocus ); } } /* reimp */ bool eventFilter( QObject * o, QEvent * e ) { if ( e->type() == QEvent::Wheel && qobject_cast<QAbstractSpinBox*>( o ) ) { e->ignore(); return true; } return QWidget::eventFilter( o, e ); }
Правка от Гранта Лимберга для полноты, поскольку это дало мне 90% пути туда:
В дополнение к тому, что ммутц сказал выше, мне нужно было сделать еще несколько вещей. Мне пришлось создать подкласс QSpinBox и реализоватьfocusInEvent(QFocusEvent*)иfocusOutEvent(QFocusEvent*). В основном, наfocusInEvent, Я изменяю политику фокусировки наQt::WheelFocus, а наfocusOutEventя изменяю ее обратно наQt::StrongFocus.void MySpinBox::focusInEvent(QFocusEvent*) { setFocusPolicy(Qt::WheelFocus); } void MySpinBox::focusOutEvent(QFocusEvent*) { setFocusPolicy(Qt::StrongFocus); }Кроме того, реализация метода eventFilter в классе фильтров событий изменяет его поведение на основе текущей политики фокусировки подкласса spinbox:
bool eventFilter(QObject *o, QEvent *e) { if(e->type() == QEvent::Wheel && qobject_cast<QAbstractSpinBox*>(o)) { if(qobject_cast<QAbstractSpinBox*>(o)->focusPolicy() == Qt::WheelFocus) { e->accept(); return false; } else { e->ignore(); return true; } } return QWidget::eventFilter(o, e); }
Чтобы решить эту проблему, нам нужно позаботиться о двухследующих вещах:
- вращающаяся коробка не должнаполучать фокус с помощью колеса мыши. Это можно сделать, установив политику фокусировки в
Спиновая коробка должна принимать события колеса только в том случае, если она уже имеет фокус. Это может быть сделано путем повторного включенияQt::StrongFocus.QWidget::wheelEventв подклассQSpinBox.Полный код для класса
MySpinBox, который реализует это:class MySpinBox : public QSpinBox { Q_OBJECT public: MySpinBox(QWidget *parent = 0) : QSpinBox(parent) { setFocusPolicy(Qt::StrongFocus); } protected: virtual void wheelEvent(QWheelEvent *event) { if (!hasFocus()) { event->ignore(); } else { QSpinBox::wheelEvent(event); } } };Вот и все. Обратите внимание, что если вы не хотите создавать новый подкласс
QSpinBox, то вы также можете использовать фильтры событий вместо этого, чтобы решить эту проблему.
Моя попытка найти решение. Простота в использовании, не требуется подклассов.
Сначала я создал новый вспомогательный класс:
#include <QObject> class MouseWheelWidgetAdjustmentGuard : public QObject { public: explicit MouseWheelWidgetAdjustmentGuard(QObject *parent); protected: bool eventFilter(QObject* o, QEvent* e) override; }; #include <QEvent> #include <QWidget> MouseWheelWidgetAdjustmentGuard::MouseWheelWidgetAdjustmentGuard(QObject *parent) : QObject(parent) { } bool MouseWheelWidgetAdjustmentGuard::eventFilter(QObject *o, QEvent *e) { const QWidget* widget = static_cast<QWidget*>(o); if (e->type() == QEvent::Wheel && widget && !widget->hasFocus()) { e->ignore(); return true; } return QObject::eventFilter(o, e); }Затем я установил политику фокусировки проблемного виджета на
StrongFocus, либо во время выполнения, либо в Qt Designer. А затем я устанавливаю свой фильтр событий:
ui.comboBox->installEventFilter(new MouseWheelWidgetAdjustmentGuard(ui.comboBox));Готово.
MouseWheelWidgetAdjustmentGuardбудет удален автоматически, когда родительский объект-combobox-будет уничтожен.
Просто для расширения вы можете сделать это с помощью eventFilter вместо того, чтобы удалить необходимость наследования нового класса типа QMySpinBox:
bool eventFilter(QObject *obj, QEvent *event) { QAbstractSpinBox* spinBox = qobject_cast<QAbstractSpinBox*>(obj); if(spinBox) { if(event->type() == QEvent::Wheel) { if(spinBox->focusPolicy() == Qt::WheelFocus) { event->accept(); return false; } else { event->ignore(); return true; } } else if(event->type() == QEvent::FocusIn) { spinBox->setFocusPolicy(Qt::WheelFocus); } else if(event->type() == QEvent::FocusOut) { spinBox->setFocusPolicy(Qt::StrongFocus); } } return QObject::eventFilter(obj, event); }
Просто чтобы помочь кому-то в нужде, ему не хватает маленькой детали:
call focusInEvent and focusOutEvent from QSpinBox : void MySpinBox::focusInEvent(QFocusEvent* pEvent) { setFocusPolicy(Qt::WheelFocus); QSpinBox::focusInEvent(pEvent); } void MySpinBox::focusOutEvent(QFocusEvent*) { setFocusPolicy(Qt::StrongFocus); QSpinBox::focusOutEvent(pEvent); }
С помощью этого поста мы приготовили решение для Python/PySide. Если кто-то наткнется на это. Как мы сделали :]
class HumbleSpinBox(QtWidgets.QDoubleSpinBox): def __init__(self, *args): super(HumbleSpinBox, self).__init__(*args) self.setFocusPolicy(QtCore.Qt.StrongFocus) def focusInEvent(self, event): self.setFocusPolicy(QtCore.Qt.WheelFocus) super(HumbleSpinBox, self).focusInEvent(event) def focusOutEvent(self, event): self.setFocusPolicy(QtCore.Qt.StrongFocus) super(HumbleSpinBox, self).focusOutEvent(event) def wheelEvent(self, event): if self.hasFocus(): return super(HumbleSpinBox, self).wheelEvent(event) else: event.ignore()
Comments