QSpinBox внутри QScrollArea: Как предотвратить Spin Box от кражи фокуса при прокрутке? - PullRequest
21 голосов
/ 28 апреля 2011

У меня есть элемент управления с несколькими объектами QSpinBox внутри QScrollArea. Все отлично работает при прокрутке в области прокрутки, если только мышь не оказывается над одним из QSpinBoxes. Затем QSpinBox крадет фокус, а события колеса манипулируют значением поля прокрутки, а не прокручивают область прокрутки.

Я не хочу полностью отключать использование колесика мыши для манипулирования QSpinBox, но я хочу, чтобы это происходило только в том случае, если пользователь явно щелкает или вкладывает вкладку в QSpinBox. Есть ли способ, чтобы QSpinBox не мог украсть фокус у QScrollArea?

Как сказано в комментарии к ответу ниже, установка Qt :: StrongFocus действительно предотвращает появление прямоугольника фокуса на элементе управления, однако он все еще крадет колесо мыши и регулирует значение в поле прокрутки и останавливает прокрутку QScrollArea , То же самое с Qt :: ClickFocus.

Ответы [ 6 ]

16 голосов
/ 28 апреля 2011

Попробуйте удалить Qt::WheelFocus из spinbox '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);
}
13 голосов
/ 15 октября 2013

Чтобы решить эту проблему, нам нужно позаботиться о двух следующих вещах:

  1. Поле вращения не должно фокусироваться с помощью колесика мыши. Это можно сделать, установив политику фокусировки на Qt::StrongFocus.
  2. Вращающаяся коробка должна принимать события колеса только в том случае, если у нее уже есть фокус . Это можно сделать, переопределив 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, вы можете вместо этого использовать фильтры событий, чтобы решить эту проблему.

9 голосов
/ 26 мая 2016

Моя попытка решения.Простой в использовании, не требует подклассов.

Сначала я создал новый вспомогательный класс:

#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 будет автоматически удален при уничтожении родительского объекта - списка.

3 голосов
/ 15 июля 2013

Просто для расширения вы можете сделать это с помощью 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);
}
2 голосов
/ 29 августа 2018

С помощью этого поста мы приготовили решение для 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()
0 голосов
/ 05 сентября 2013

Просто, чтобы помочь кому-то нуждающемуся, ему не хватает маленькой детали:

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);
    }
...