问题
I am using Qt 5.3.2
with Qt Creator 3.2.1
with MinGW 4.8.2
on Windows 7
. I have a QSpinBox
and can change its value with the mouse wheel only if the mouse is over the QSpinBox
. If the mouse is not over the QSpinBox
, scrolling the mouse wheel has no effect, even though the QSpinBox
still has focus. What do I need to do to be able to change values in the QSpinBox
that has focus with the mouse wheel even if the mouse is not hovering over it? Setting mouseTracking
to true
does not have that effect.
回答1:
Use eventFilter
to do this. Install it on your mainWindow
:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
if(wheelEvent->delta() > 0)
ui->spinBox->setValue(ui->spinBox->value() + 1);
else
ui->spinBox->setValue(ui->spinBox->value() - 1);
}
}
It is just example, so you can improve it as you want.
Or use this:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QApplication::sendEvent(ui->spinBox,event);
}
}
In this example, when you detect wheel event, you send it to your spinbox.
But don't forget
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
As DmitrySazonov
recommended. We will detect wheelEvents when our spinBox in focus, when spinBox losed focus, we don't react on wheel(other widgets react normal). We do this in one eventFilter. To do this provide new bool variable. For example:
private:
bool spin;//in header
Initialize it in constructor:
spin = false;
And your eventFilter should be.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->spinBox && event->type() == QEvent::FocusIn)
spin = true;
if(spin)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QApplication::sendEvent(ui->spinBox,event);
}
}
if(obj == ui->spinBox && event->type() == QEvent::FocusOut)
spin = false;
}
Or do just this, without additional variable:
if (obj == this && event->type() == QEvent::Wheel)
{
if(ui->spinBox->hasFocus())
QApplication::sendEvent(ui->spinBox,event);
}
回答2:
I did not mention it in the question but I have more that one QSpinBox
and testing them all seems sub-optimal, so I need a generic message forwarder. Based on the Chernobyl's code I made my own version of the message filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event){
if (obj == this && event->type() == QEvent::Wheel)
{
auto focusWidget = QApplication::focusWidget();
if (focusWidget){
qApp->removeEventFilter(this);
QApplication::sendEvent(focusWidget, event);
qApp->installEventFilter(this);
return true;
}
}
return false;
}
This forwards all QWheelEvent
s to the QWidget
with the focus. One could also add other events that need to be forwarded.
The qApp->removeEventFilter
and qApp->installEventFilter
inside the event filter is the only way I found that prevents the event filter calling itself when scrolling on the main window causing a stack overflow (condition focusWidget != this
does not help). There isprobably a way to prevent the infinite recursion without reinstalling the event filter on every QWheelEvent
.
来源:https://stackoverflow.com/questions/26041471/make-qspinbox-react-to-mouse-wheel-events-when-cursor-is-not-over-it