QScrollArea中的QSpinBox:如何防止旋转框在滚动时窃取焦点
QSpinBox inside a QScrollArea: How to prevent Spin Box from stealing focus when scrolling?
我有一个控件,在QScrollArea中有几个QSpinBox对象。在滚动区域中滚动时,所有工作正常,除非鼠标恰好位于其中一个qspinbox上。然后QSpinBox窃取焦点,wheel事件操纵旋转框的值,而不是滚动滚动区域。
我不想完全禁用使用鼠标滚轮来操作QSpinBox,但我只希望在用户显式单击或tab进入QSpinBox时发生这种情况。是否有一种方法可以防止QSpinBox从QScrollArea窃取焦点?
正如在下面的回答评论中所说,设置Qt::StrongFocus确实可以防止焦点矩形出现在控件上,但是它仍然会窃取鼠标滚轮并调整旋转框中的值并阻止QScrollArea滚动。Qt::ClickFocus也是一样。
为了解决这个问题,我们需要关心两个以下内容:
- 旋转框不能通过鼠标滚轮获得焦点。这可以通过将焦点策略设置为
Qt::StrongFocus
来完成。 - 旋转框必须只有在已经有焦点时才接受滚轮事件。这可以通过在
QSpinBox
子类中重新实现QWidget::wheelEvent
来完成。
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
子类,那么您也可以使用事件过滤器来解决这个问题。
尝试从spinbox中移除Qt::WheelFocus
' QWidget::focusPolicy
:
spin->setFocusPolicy( Qt::StrongFocus );
另外,你需要防止wheel事件到达spinbox。您可以使用事件过滤器:
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 );
}
来自Grant Limberg的编辑,因为这让我完成了90%的工作:
除了mmutz上面说的,我还需要做一些其他的事情。我必须创建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方法实现根据自旋盒子类的当前焦点策略更改其行为:
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);
}
我的解决方案。易于使用,不需要子类化。
首先,我创建了一个新的助手类:#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设计器中。然后我安装我的事件过滤器:
ui.comboBox->installEventFilter(new MouseWheelWidgetAdjustmentGuard(ui.comboBox));
。当父对象(组合框)被销毁时,MouseWheelWidgetAdjustmentGuard
将被自动删除。
只是为了展开,您可以使用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);
}
这是我的Python PyQt5端口紫罗兰长颈鹿的答案:
def preventAnnoyingSpinboxScrollBehaviour(self, control: QAbstractSpinBox) -> None:
control.setFocusPolicy(Qt.StrongFocus)
control.installEventFilter(self.MouseWheelWidgetAdjustmentGuard(control))
class MouseWheelWidgetAdjustmentGuard(QObject):
def __init__(self, parent: QObject):
super().__init__(parent)
def eventFilter(self, o: QObject, e: QEvent) -> bool:
widget: QWidget = o
if e.type() == QEvent.Wheel and not widget.hasFocus():
e.ignore()
return True
return super().eventFilter(o, e)
在这篇文章的帮助下,我们为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()
只是为了帮助任何需要帮助的人,缺少一个小细节:
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);
}
- 使用一个考虑到std::map中键值的滚动或换行的键
- QScrollArea:由垂直滚动条引起的水平滚动条
- 跟踪滚动条上的鼠标事件
- 如何在不使用滚动条的情况下使视图更改
- 如何为对象生成滚动效果?
- 如何模拟不同边数的骰子滚动?
- 如何初始化升压滚动窗口累加器?
- 有没有办法区分Qt小部件是通过鼠标单击还是通过按表键获得焦点?
- 实现包含多个 QQuickPaintedItems 的 QQuickView 的滚动
- MFC:如何设置CEdit框的焦点?
- 通过水平滚动条更改标签
- 如何防止 Windows 控制台上的回车键自动滚动
- Qt:无法直接为带有子项的小部件添加滚动条
- OnVScroll : 从 CSpinButtonCtrl 或垂直滚动条调用?
- win32 滚动条在 C/C++ 程序中不起作用
- 在 ubuntu 焦点上编译虚幻引擎 4.25 时出错
- 为什么玩家控制器"own"偏航俯仰和滚动,但角色"owns"它的位置?
- 外观 MFC 滚动条
- 如何在 wxWidgets 中从 wxTextCtrl 中删除焦点
- QScrollArea中的QSpinBox:如何防止旋转框在滚动时窃取焦点