QSpinBox внутри QScrollArea: как предотвратить спин-бокс от кражи фокуса при прокрутке?
У меня есть элемент управления с несколькими объектами QSpinBox внутри QScrollArea. Все работает нормально при прокрутке в области прокрутки, если мышь не находится над одним из QSpinBoxes. Затем QSpinBox крадет фокус, а события колеса манипулируют значением поля вращения, а не прокруткой области прокрутки.
Я не хочу полностью отключать использование колесика мыши для управления QSpinBox, но я хочу, чтобы это произошло, только если пользователь явно нажимает или вкладывает в QSpinBox. Есть ли способ предотвратить кражу фокуса QSpinBox из QScrollArea?
Как сказано в комментарии к ответу ниже, установка Qt:: StrongFocus предотвращает появление фокуса rect на элементе управления, однако он по-прежнему крадет колесо мыши и регулирует значение в поле вращения и останавливает прокрутку QScrollArea. То же самое с Qt::ClickFocus.
6 ответов
Попробуйте удалить Qt::WheelFocus
из spinbox'QWidget::focusPolicy
:
spin->setFocusPolicy( Qt::StrongFocus );
кроме того, вам нужно предотвратить событие колеса от достижения spinboxes. Вы можете сделать это с помощью фильтра событий:
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 );
}
edit от Гранта Лимберга для полноты, так как это дало мне 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));
сделано. The 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()