Search code examples
c++qtmouseeventeventfilter

How to make a widget transparent for selected mouse events


I'm working with a QDial object that is intended to be controlled with a mouse wheel, it works fine as such, emitting valueChanged() signals when necessary.

I would like to put a semi-transparent QToolButton on top of it, allowing users to click on the button (and set QDial value to a pre-defined number) while maintaining the ability to use the mouse wheel to control QDial as usual.

I experimented a bit with the TransparentForMouseEvents attribute:

ui->toolButton_Example->setAttribute(Qt::WA_TransparentForMouseEvents);

The problem is, the above code switches off all events, including the ability to emit the clicked() signal.

Is there a way to make a QToolButton transparent selectively for MouseWheelEvents while preserving the ability to respond to MouseClick events? Or would this require rewriting the event filter from scratch?

Just to clarify, this question is about making QToolButton being transparent to MouseWheel events while still allowing it to respond to MouseClick events. It is not about making the button transparent in the graphical sense.


Solution

  • You can use QObject::installEventFilter to have the parent object filter the events before they reach the tool button. Then, override the parent's QObject::eventFilter to handle/ignore the event.

    I create an example below:

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QToolButton>
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
        bool eventFilter(QObject *watched, QEvent *event) override;
    
    private:
        QToolButton tool_button_ignored_;
        QToolButton tool_button_handled_;
    };
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    
    #include <QDebug>
    #include <QEvent>
    #include <QHBoxLayout>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        tool_button_ignored_.setObjectName("tool_button_ignored_");
        tool_button_ignored_.setText("Ignored button");
        tool_button_ignored_.installEventFilter(this);
    
        tool_button_handled_.setObjectName("tool_button_handled_");
        tool_button_handled_.setText("Handled button");
        tool_button_handled_.installEventFilter(this);
    
        QWidget *central_widget = new QWidget{this};
        QHBoxLayout *layout = new QHBoxLayout{central_widget};
        layout->addWidget(&tool_button_ignored_);
        layout->addWidget(&tool_button_handled_);
        this->setCentralWidget(central_widget);
    }
    
    MainWindow::~MainWindow()
    {
    }
    
    bool MainWindow::eventFilter(QObject *watched, QEvent *event)
    {
        if (watched != &tool_button_ignored_ || event->type() != QEvent::Wheel)
        {
            qDebug() << event->type() << watched->objectName() << "handled";
            return QMainWindow::eventFilter(watched, event);
        }
        else
        {
            qDebug() << event->type() << watched->objectName() << "ignored";
            return true; // stop being handled further
        }
    }