Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Multiplatform QML Menus
Forum Updated to NodeBB v4.3 + New Features

Multiplatform QML Menus

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
7 Posts 3 Posters 796 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Citron
    wrote on 7 Jan 2024, 02:28 last edited by Citron 1 Jul 2024, 02:53
    #1

    Hi,
    I have a question regarding native QML menus. I have a macOS app that works well. To handle menus, I use the Qt.labs.platform module, which has a MenuBar that creates a native macOS menu.
    But I'm now in the process of porting that application to Windows. And I have no clue what to do to make the menu bar appear somewhere in my window. It's clearly stated in the doc that Windows is supported so I'm assuming this is meant to work on that platform too :/

    Am I missing something obvious here?

    And if the doc is incorrect, or for some other reason I can't use the same module on Windows to handle the menu: how can I go about to have a menu that work on both platform? I could conditionally import Qt.labs.platform if I'm on macOS, otherwise use the QtQuick.Controls version.. that is if there was a way to do that?
    Edit: well, that wouldn't even work since the name for the "shortcut" is "sequence" in the QtQuick.Controls version..

    Any help appreciated!

    K 1 Reply Last reply 8 Jan 2024, 16:35
    0
    • C Citron
      7 Jan 2024, 02:28

      Hi,
      I have a question regarding native QML menus. I have a macOS app that works well. To handle menus, I use the Qt.labs.platform module, which has a MenuBar that creates a native macOS menu.
      But I'm now in the process of porting that application to Windows. And I have no clue what to do to make the menu bar appear somewhere in my window. It's clearly stated in the doc that Windows is supported so I'm assuming this is meant to work on that platform too :/

      Am I missing something obvious here?

      And if the doc is incorrect, or for some other reason I can't use the same module on Windows to handle the menu: how can I go about to have a menu that work on both platform? I could conditionally import Qt.labs.platform if I'm on macOS, otherwise use the QtQuick.Controls version.. that is if there was a way to do that?
      Edit: well, that wouldn't even work since the name for the "shortcut" is "sequence" in the QtQuick.Controls version..

      Any help appreciated!

      K Offline
      K Offline
      KH-219Design
      wrote on 8 Jan 2024, 16:35 last edited by
      #2

      Just an intuition, but I feel it is highly likely there are QML "warnings" being output to the console (whatever Windows uses for stderr, stdout).

      I say "warnings" in "scare quotes" because I consider many of these to actually represent critical errors for a UI, but nonetheless, due to the interpreted (or semi-compiled/semi-interpreted) nature of QML, these happen at runtime and understandably Qt has chosen to let the app continue running and not crash.

      However, many of these represent flaws in your QML usage that prevent your UI from being usable. You may have already experienced these on MacOS but somehow had 'luck' and the UI was able to recover. Now, on another platform, either there are new warnings or the UI is somehow unable to recover from the preexisting ones.

      Examples of what you might see:

          "Apparently out-of-range date",
          "called when not loading",
          "can't resolve property alias for 'on' assignment",
          "Cannot create a component",
          "Cannot create new component instance",
          "Cannot pause a stopped animation",
          "Cannot set context object",
          "Cannot set property",
          "Component creation is recursing",
          "Component destroyed while completion pending",
          "Component is not ready",
          "Could not convert argument",
          "Could not convert array value",
          "Cyclic dependency detected ",
          "cyclic prototype value",
          "Detected anchors on an item that is managed by a layout",
          "emitted, but no receivers connected to handle it",
          "Failed to get image from provider",
          "failed to load component",
          "insertAnimation only supports to add animations after the current one",
          "Model size of",  # "...is less than 0" AND/OR "...is bigger than upper limit"
          "Must provide an engine",
          "QML LoaderImage",
          "qmlRegisterSingletonType requires absolute URLs",
          "qmlRegisterType requires absolute URLs",
          "ReferenceError:",
          "specifying the encoding as fourth argument is deprecated",
          "TypeError",
          "Unable to assign",
          "Unable to handle unregistered datatype",
          "unregistered datatype",
      

      www.219design.com
      Software | Electrical | Mechanical | Product Design

      1 Reply Last reply
      0
      • J Offline
        J Offline
        jeremy_k
        wrote on 9 Jan 2024, 20:34 last edited by
        #3

        I don't know about the menu-specific portion of the question.

        QQmlFileSelector is intended to support similar use cases by placing platform-specific components in different directories.

        This can be also be implemented via a Loader and a switch or if-else keying off of platform.os.

        Asking a question about code? http://eel.is/iso-c++/testcase/

        C 1 Reply Last reply 10 Jan 2024, 18:59
        1
        • J jeremy_k
          9 Jan 2024, 20:34

          I don't know about the menu-specific portion of the question.

          QQmlFileSelector is intended to support similar use cases by placing platform-specific components in different directories.

          This can be also be implemented via a Loader and a switch or if-else keying off of platform.os.

          C Offline
          C Offline
          Citron
          wrote on 10 Jan 2024, 18:59 last edited by
          #4

          @jeremy_k Interesting, I didn't know of that one. I'll have a look, thanks!

          It won't solve all the problems though: since the Qt.labs menu bar is displayed on the macOS menu, the content of my app is anchored to the whole window. Whereas the QtQuick.controls menu bar is displayed inside the window, so I the anchoring can no longer be the whole window on Linux/Windows. And this can't be solved in QML also because the Qt.labs menu bar doesn't support anchoring :D
          But at least for the components' implementation, this seems like a viable solution!

          (note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish". But I really wish QML had at least a very rudimentary preprocessor capability that would allow to #ifdef parts of the code..)

          K J 2 Replies Last reply 10 Jan 2024, 20:24
          0
          • C Citron
            10 Jan 2024, 18:59

            @jeremy_k Interesting, I didn't know of that one. I'll have a look, thanks!

            It won't solve all the problems though: since the Qt.labs menu bar is displayed on the macOS menu, the content of my app is anchored to the whole window. Whereas the QtQuick.controls menu bar is displayed inside the window, so I the anchoring can no longer be the whole window on Linux/Windows. And this can't be solved in QML also because the Qt.labs menu bar doesn't support anchoring :D
            But at least for the components' implementation, this seems like a viable solution!

            (note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish". But I really wish QML had at least a very rudimentary preprocessor capability that would allow to #ifdef parts of the code..)

            K Offline
            K Offline
            KH-219Design
            wrote on 10 Jan 2024, 20:24 last edited by
            #5

            @Citron said in Multiplatform QML Menus:

            note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish".

            @Citron I'm very curious: What kinds of snippets did you have to inject? I'm interested in seeing what kind of extra code was effective in getting the Qt.labs.platform MenuBar to work on Windows.

            www.219design.com
            Software | Electrical | Mechanical | Product Design

            C 1 Reply Last reply 15 Jan 2024, 19:39
            0
            • C Citron
              10 Jan 2024, 18:59

              @jeremy_k Interesting, I didn't know of that one. I'll have a look, thanks!

              It won't solve all the problems though: since the Qt.labs menu bar is displayed on the macOS menu, the content of my app is anchored to the whole window. Whereas the QtQuick.controls menu bar is displayed inside the window, so I the anchoring can no longer be the whole window on Linux/Windows. And this can't be solved in QML also because the Qt.labs menu bar doesn't support anchoring :D
              But at least for the components' implementation, this seems like a viable solution!

              (note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish". But I really wish QML had at least a very rudimentary preprocessor capability that would allow to #ifdef parts of the code..)

              J Offline
              J Offline
              jeremy_k
              wrote on 10 Jan 2024, 23:04 last edited by
              #6

              @Citron said in Multiplatform QML Menus:

              @jeremy_k Interesting, I didn't know of that one. I'll have a look, thanks!

              It won't solve all the problems though: since the Qt.labs menu bar is displayed on the macOS menu, the content of my app is anchored to the whole window. Whereas the QtQuick.controls menu bar is displayed inside the window, so I the anchoring can no longer be the whole window on Linux/Windows. And this can't be solved in QML also because the Qt.labs menu bar doesn't support anchoring :D

              I suspect this merely requires a little more creative thinking. Something along the lines of:
              anchors.top: os.platform != "macOS" ? menu.bottom : undefined

              (note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish". But I really wish QML had at least a very rudimentary preprocessor capability that would allow to #ifdef parts of the code..)

              Component + Loader with conditional use, or define the component as a string and dynamically instantiate it.

              Asking a question about code? http://eel.is/iso-c++/testcase/

              1 Reply Last reply
              0
              • K KH-219Design
                10 Jan 2024, 20:24

                @Citron said in Multiplatform QML Menus:

                note: to solve this, I ended up using CMake's configure_file to inject platform specific snippets where necessary. It ended up being "okay'ish".

                @Citron I'm very curious: What kinds of snippets did you have to inject? I'm interested in seeing what kind of extra code was effective in getting the Qt.labs.platform MenuBar to work on Windows.

                C Offline
                C Offline
                Citron
                wrote on 15 Jan 2024, 19:39 last edited by Citron
                #7

                @jeremy_k Yes you're right, I totally forgot that it's valid to assign undefined to anchors, so this can be handled dynamically.

                @KH-219Design I didn't try to make Qt.labs MenuBar work on Windows. On Windows I'm using the regular QtQuick.Controls MenuBar. So the QML code for defining the menu in my app is the same on both platform. I just have to inject the import Qt.labs.platform when I'm on macOS (and a few other "patches" because there are some slight differences between Qt.labs and QtQuick.Controls implementations of menu items) Basically I'm just re-creating the ability to have #if/#else chunks of code in QML...

                Basically in the header part of my QML, I have a @MACOS_IMPORT_STATEMENT which CMake replaces by import Qt.labs.platform as Labs on macOS and nothing on other platforms.
                And in my main window code, I have something like:

                @MENU_DEFINITIONS@
                
                MenuBar_ {
                    Menu_ {
                        title: "Application"
                
                        MenuItem_ {
                            text: "Preferences"
                            shortcut: Qt.platform.os === "windows" ? "Ctrl+P" : StandardKey.Preferences
                            onTriggered: preferences.open()
                        }
                
                        MenuSeparator {}
                
                        MenuItem_ {
                            text: "Quit"
                            // NOTE: Because for some reason Alt+F4 is not considered the standard way of quitting an app on Windows? Seriously?
                            shortcut: Qt.platform.os === "windows" ? "Alt+F4" : StandardKey.Quit
                            onTriggered: Qt.quit()
                        }
                    }
                
                    Menu_ {
                        title: "Edit"
                        // ...
                    }
                }
                

                And @MENU_DEFINITIONS@ is replaced by CMake by

                component MenuBar_ : Labs.MenuBar {}
                component Menu_ : Labs.Menu {}
                component MenuItem_ : Labs.MenuItem {}
                

                on macOS and

                component MenuBar_ : MenuBar {}
                component Menu_ : Menu {}
                component MenuItem_ : MenuItem {
                    id: ctrl
                    property alias shortcut: action.sequence
                    contentItem: RowLayout {
                        Label { text: ctrl.text; Layout.fillWidth: true }
                        Label { text: action.nativeText; enabled: false }
                    }
                    Shortcut {
                        id: action
                        enabled: ctrl.enabled
                        context: Qt.ApplicationShortcut
                        onActivated: ctrl.triggered()
                    }
                }
                

                on Windows (because I wanted to shortcuts to show up in the menu items, like it does on macOS)

                Anyway. It's still a bit annoying that such a trivial thing is so convoluted to do in QML... Yes there are components, loaders and whatnot. But: you pay a small performance price for using those: they are meant for dynamic stuff. How ofter does the same running QML code change platform? Never. Platform specific stuff should be resolved compiled time. And more importantly: using native QML "solutions" introduces a lot of boiler plate code for no good reason.

                1 Reply Last reply
                1

                1/7

                7 Jan 2024, 02:28

                • Login

                • Login or register to search.
                1 out of 7
                • First post
                  1/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved