Important: Please read the Qt Code of Conduct -

How to close dialog when mouse leaves a QWidget in the mainwindow (but not when it is over the dialog)

  • Hello,

    I have a dialog, that shows at the mouse position and is related to the underlying widget (like a right click menu for the underlying widget)

    myWidget* tool = new myWidget(this);
    myWidget->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
    QPoint p = this->mapToGlobal(QPoint(event->x(), event->y()));
    tool->setGeometry(p.x(), p.y(), 100 , 50);

    Now I want the dialog to close when the mouse leaves the underlying widget. However using leaveEvent() does not work, since as soon as the widgets appears the leave event gets triggered (which is totally what it should do)

    So how can I detect if the mouse moves outside the underlying widget?

  • @gde23

    Install an eventFilter on your widget. Let your mainWindow handle the events and close your dialog when the event is a QEvent::Leave type.

    You have to enable mouseTracking first.

  • @Pl45m4: I tried that, but the QEvent::Leave event also gets triggered when I move the mouse over the dialog (which is in front of the widget)

  • Lifetime Qt Champion


    Then apply the reverse logic: if the enter event is not from your dialog or the underlying widget, hide it.

  • @gde23

    Maybe you can make use of

    So if you leave your widget at QPointp and p belongs to your dialog, you ignore that event.

    Edit: Probably you dont even need topLevelAt for that.

  • Thanks for the ideas, I got it working like this now:

    bool myWidget::event(QEvent* e) 
        if(e->type() == QEvent::Leave) 
            QPoint view_pos(x(), y());
            QPoint view_pos_global = mapToGlobal(view_pos);
            QPoint mouse_global = QCursor::pos();
            if(mouse_global.x() < view_pos_global.x() || mouse_global.x() > view_pos_global.x() + width())
            else if(mouse_global.y() < view_pos_global.y() || mouse_global.y() > view_pos_global.y() + height())
        return QWidget::event(e);