1

I want to implement an extended "QScrollArea" widget that supports scrolling the scrollbar (contents) with the mouse by dragging the mouse somewhere within the widget. For this purpose I want to ignore any child widgets so that the focus don't accidently goes to some of the children.

My solution (which is not working) is to set content widget attribute WA_TransparentForMouseEvents so that all the mouse events goes to viewportEvent() method in my QScrollAreaEx. Here I want to handle the mouse messages. For example I could determine if the intention was to drag the scrollbar position or to interact with some of the child widgets (activate, select, move caret, ...).

My first try was to redirect the messages MouseButtonPress and MouseButtonRelease events only to the child widget underneath (widget()->childAt(e->pos())) which had been focused if WA_TransparentForMouseEvents were not set. However that didn't worked, none of the widgetd received the focus. But why?

bool viewportEvent(QEvent* e) {
    bool IsMouseEvent = e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseMove;
    QMouseEvent* me = (QMouseEvent*) e;

    bool IsHandled = false;

    if (IsMouseEvent) {
        if (e->type() == QEvent::MouseButtonPress) {
            _PressEvent = *me;
            IsHandled = true; // Eating press event
        } else if (e->type() == QEvent::MouseButtonRelease) {
            QPoint PressPoint = _PressEvent.pos();
            widget()->setAttribute(Qt::WA_TransparentForMouseEvents, false);
            QWidget* w = widget()->childAt(PressPoint);
            if (w) {
                QPoint p1 = w->mapFrom(widget(), _PressEvent.pos());
                QPoint p2 = w->mapFrom(widget(), me->pos());
                QMouseEvent* e1 = new QMouseEvent(QEvent::MouseButtonPress, p1, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
                QMouseEvent* e2 = new QMouseEvent(QEvent::MouseButtonRelease, p2, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
                QCoreApplication::postEvent(w, e1);
                QCoreApplication::postEvent(w, e2);
            }
            widget()->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        }
    }
    if (IsHandled) return true;
    return QScrollArea::viewportEvent(e);
}

Second test was:

bool viewportEvent(QEvent* e) {
    bool IsMouseEvent = e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseMove;
    QMouseEvent* me = (QMouseEvent*) e;

    bool IsHandled = false;

    if (IsMouseEvent) {
        if (e->type() == QEvent::MouseButtonPress) {
            _PressEvent = *me;
            IsHandled = true; // Eating press event
        } else if (e->type() == QEvent::MouseButtonRelease) {
            QPoint PressPoint = _PressEvent.pos();
            widget()->setAttribute(Qt::WA_TransparentForMouseEvents, false);
            QWidget* w = widget()->childAt(PressPoint);
            if (w && w != widget()) {
                QCoreApplication::sendEvent(widget(), &_PressEvent);
                QCoreApplication::sendEvent(widget(), e);
            }
            widget()->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        }
    }
    if (IsHandled) return true;
    return QScrollArea::viewportEvent(e);
}

None of them was working. Why does the redirection not work. Is there a better solution for my purpose?

4

0 回答 0