QML MenuBar hovering items with mouse pressed

500 Views Asked by At

Using Qt Quick Controls 2, you can create a "traditional" menu bar like this:

ApplicationWindow {
    id: window
    width: 320
    height: 260
    visible: true

    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            Action { text: qsTr("&New...") }
            Action { text: qsTr("&Open...") }
            Action { text: qsTr("&Save") }
            Action { text: qsTr("Save &As...") }
            MenuSeparator { }
            Action { text: qsTr("&Quit") }
        }
        Menu {
            title: qsTr("&Edit")
            Action { text: qsTr("Cu&t") }
            Action { text: qsTr("&Copy") }
            Action { text: qsTr("&Paste") }
        }
        Menu {
            title: qsTr("&Help")
            Action { text: qsTr("&About") }
        }
    }
}

This works ok, but when the user presses on a menu and then drag the mouse while pressed, on the menus are not hovered. In order to hover over the menus, the mouse cannot be in a pressed state (using Qt Widgets https://doc.qt.io/qt-5/qtwidgets-mainwindows-menus-example.html this is not needed). Is there a way to make the MenuBar, hover over items while the mouse is pressed?

2

There are 2 best solutions below

0
Benjamin T On

There is not an easy way. The underlying issue is that MenuItem is implemented as a Button.

When you press a button and release on another button, none of them register a click.

However, on traditional menus, if you press an item and release on another one, the item that registers the release is triggered.

The public API offered by QtQuick Controls 2 does not seem to offer a way to easily change this. So to get what you want Isee the following solutions:

  • Use Qt.labs.platform to build your menus, these will be native menus so they should have the correct behavior. However it still in a preview state and i have not tested them.
  • Reimplement MenuItem. Since it is part of Qt Quick Controls 2 it is easy to reimplement your own MenuItem, see Qt documentation. However, you will have to use MouseArea to catch user inputs and force the behavior you want.

EDIT

The 2nd solution won't work. In Qt once an Item (or a QWidget) accepts a press event, it grabs the mouse until it is released. So reimplementing MenuItem and adding MouseArea to them won't help.

Knowing that it seems that the solution would to reproduce what QMenu is doing: You need to have a single Item responsible for handling mouse events. So you should not let each MenuItem handles mouse events individually. Instead you should handle mouse events at the Menu or MenuBar level, process the events and manually change the MenuItems.

At this point I do not know if it is easier to customize Menu and MenuItem or to jus write your own Menu from scratch.

5
user3450148 On

When you did through this doc

https://doc.qt.io/qt-5/qml-qtquick-controls2-action.html

You then go to this doc and have high hopes when reading about "hoverEnabled"

https://doc.qt.io/qt-5/qml-qtquick-controls2-toolbutton-members.html

You really need these two signals entered() exited() from a MouseArea.

https://doc.qt.io/qt-5/qml-qtquick-mousearea.html

The short hopeful hack is to see if the documentation is "just wrong" and somewhere deep in the class structure they declared a MouseArea for a button and you really do get entered() and exited().

How else would you be able to implement hoverEnabled()? The "widget" has to know the mouse entered and did not yet exit. They may well be consuming that, but you should be able to dig through the source and find child entity that you can connect to the signal of.