Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Custom context menu on disabeld widget... ?



  • Hey

    Is there a way to enable custom context menu on a widget that is disabled? I'd like to still be able to right click on it.

    TIA.



  • Hi.

    You can use the functions, but I do not test its valid range:

    void QObject::installEventFilter(QObject *filterObj);
    virtual bool QObject::eventFilter(QObject *watched, QEvent *event);
    
    bool QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
    {
        ...
    
        // send to all receiver event filters
        if (sendThroughObjectEventFilters(receiver, e)) {
            filtered = true;
            return filtered;
        }
    
        // deliver the event
        consumed = receiver->event(e);
    
        QCoreApplicationPrivate::setEventSpontaneous(e, false);
        return consumed;
    }
    

    The differentiation is at:

    bool QAbstractButton::event(QEvent *e)
    {
        // as opposed to other widgets, disabled buttons accept mouse
        // events. This avoids surprising click-through scenarios
        if (!isEnabled()) {
            switch(e->type()) {
            case QEvent::TabletPress:
            case QEvent::TabletRelease:
            case QEvent::TabletMove:
            case QEvent::MouseButtonPress:
            case QEvent::MouseButtonRelease:
            case QEvent::MouseButtonDblClick:
            case QEvent::MouseMove:
            case QEvent::HoverMove:
            case QEvent::HoverEnter:
            case QEvent::HoverLeave:
            case QEvent::ContextMenu:
    #if QT_CONFIG(wheelevent)
            case QEvent::Wheel:
    #endif
                return true;
            default:
                break;
            }
        }
    
    #ifndef QT_NO_SHORTCUT
        if (e->type() == QEvent::Shortcut) {
            Q_D(QAbstractButton);
            QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
            if (d->shortcutId != se->shortcutId())
                return false;
            if (!se->isAmbiguous()) {
                if (!d->animateTimer.isActive())
                    animateClick();
            } else {
                if (focusPolicy() != Qt::NoFocus)
                    setFocus(Qt::ShortcutFocusReason);
                window()->setAttribute(Qt::WA_KeyboardFocusChange);
            }
            return true;
        }
    #endif
        return QWidget::event(e);
    }
    

    This is my test:

    #include "mainwindow.h"
    #include "pushbutton.h"
    #include "ui_mainwindow.h"
    
    #include <QContextMenuEvent>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        b1_ = new PushButton("b1", this);
        b1_->move(100, 100);
        b1_->setDisabled(true);
        b2_ = new PushButton("b2", this);
        b2_->move(200, 200);
    
        setObjectName("mainwindow");
        b1_->setObjectName("b1");
        b2_->setObjectName("b2");
    
        b1_->installEventFilter(this);
        b2_->installEventFilter(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::contextMenuEvent(QContextMenuEvent *event)
    {
        QMenu* menu = new QMenu(this);
        menu->addAction("a1");
        menu->addAction("a2");
        menu->addAction("a3");
        menu->exec(event->globalPos());
    
        QWidget::contextMenuEvent(event);
    }
    
    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        if (event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent* e = static_cast<QMouseEvent*>(event);
    
            if (obj == b1_ && (e->button() == Qt::RightButton) )
            {
                // Do what you want
                QMenu* menu = new QMenu(this);
                menu->addAction("c1");
                menu->addAction("c2");
                menu->addAction("c3");
                menu->exec(e->globalPos());
                return true;
            }
        }
    
        return QObject::eventFilter(obj, event);
    }
    


  • event() is a vfun, so you also can do that:

    bool PushButton::event(QEvent *event)
    {
        if (event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent* e = static_cast<QMouseEvent*>(event);
    
            if (e->button() == Qt::RightButton)
            {
                // Do what you want
                QMenu* menu = new QMenu(this);
                menu->addAction("d1");
                menu->addAction("d2");
                menu->addAction("d3");
                menu->exec(e->globalPos());
                return true;
            }
        }
    
        return QPushButton::event(event);
    }
    
    

Log in to reply