[Interest] Change modifier for horizontal scrolling with mousewheel

Volker Hilsheimer volker.hilsheimer at qt.io
Fri May 20 20:23:08 CEST 2022



> On 20 May 2022, at 17:26, Sean Murphy via Interest <interest at qt-project.org> wrote:
> 
> The subject mostly says it all - is there a way to change the modifier used to allow horizontal scrolling with mousewheel?
> 
> By default it appears that Alt + mousewheel in a QScrollArea (and QGraphicsView, etc.) scrolls horizontally, but I have a user that wants that to be Shift + mouse wheel instead... Fine, I'll add some settings in my Options dialog to allow users to customize which key modifiers do what, but then I need to make it happen.
> 
> I think I can accomplish this by adding an event filter. The issue I see is that the existing Alt + mousewheel behaves just like I want - scroll direction sense is the way I want it, scroll size seems sensible for a single mouse wheel bump, and I don't see anywhere in the API where I can query what that scroll step size is to duplicate it.
> 
> Any tips/tricks? Ideally, could I just trap the users actual event, but then turn around and send an Alt+mousewheel event to the widget? That way I get the default scrolling behavior, but I'm just inserting a custom modifier layer over the top?
> 
> Sean

Hi Sean,

The Alt modifier key being pressed while wheeling gets interpreted very far down in the Qt stack, when our various QPA plugins translate the native event into what ultimately becomes a QWheelEvent. Simply sending a synthesized wheel event with the Alt modifier set to the QWidget will not trigger this behavior, as that never exercises that QPA code.

What QAbstractScrollArea does by default is that it checks whether the angleDelta of the wheel event is mostly in the x- or mostly in the y-direction, and then sends the wheel event on to the respective scrollbar:


void QAbstractScrollArea::wheelEvent(QWheelEvent *e)
{
    Q_D(QAbstractScrollArea);
    if (qAbs(e->angleDelta().x()) > qAbs(e->angleDelta().y()))
        QCoreApplication::sendEvent(d->hbar, e);
    else
        QCoreApplication::sendEvent(d->vbar, e);
}


So, in subclasses of your QAbstractScrollArea widgets you could check whether the Shift key is pressed, and then construct a QWheelEvent into which you copy all the attributes from the original event, but transpose the angleDelta. Then send that event to the respective scroll bar (shift held while angleDelta.y > angleDelta.x -> horizontal scroll bar). Remember to accept/ignore the original event based on how your synthesized event came back (calling QEvent::setAccepted/isAccepted).

If you want to also disable the Alt modifier’s effect, then things get a bit trickier (if Alt is held, assume that the original event is flipped, so unflip it).

If you want this to be the UX for all your QAbstractScrollArea widgets, then you can install an event filter on the viewport of all of them. You could also try to override QApplication::notify, and call the parent class implementation with your flipped QWheelEvent. In that case, only apply your logic if the original event has the QEvent::spontaneous bit set. However, that will then also impact widgets such as a tab bar or a spinbox unless you use qobject_cast to verify that the receiver’s parent is a QAbstractScrollArea.

Lastly, you probably don’t want to do any of this when the original wheel event comes from a kinetic scrolling device (like a track pad), so check QWheelEvent::phase and only do this when it’s Qt::NoScrollPhase.

Volker



More information about the Interest mailing list