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

Disabling/enabling system menu items?



  • Does anyone have a working example of how to disable and enable items in the system menu on Windows?

    I've tried:

    EnableMenuItem(), which changes the flags for the item but doesn't actually disable it,

    SetWindowLong(), which doesn't seem to do anything,

    and,

    ModifyMenu() with GetMenuItemInfo(), which disables the item but when re-enabled no longer sends a windows command when clicked.

    I need to be able to temporarily disable an item and re-enable it later, for use with a frameless window.



  • Update: so I put this into the constructor of one of my widgets:

      QTimer::singleShot(2500, [=] {
        EnableMenuItem(system_menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_DISABLED);
      });
    

    With the menu open, after the timer executes, the maximize item is disabled, but when I close the menu and reopen it the maximize item is re-enabled.


  • Moderators

    If you want to disable maximizing of the window you should do that via window flags, for example in the constructor:

    MainWindow::MainWindow(QWidget *parent)
      : QMainWindow(parent
                   , Qt::Window
                   | Qt::CustomizeWindowHint
                   | Qt::WindowSystemMenuHint
                   | Qt::WindowMinimizeButtonHint
                   | Qt::WindowCloseButtonHint)
                   , ui(new Ui::MainWindow)
    {
       ...
    

    This will disable all the ways a window can be maximized (like aero snap or double click on the title bar), not just via system menu.

    But if you really want to fiddle with the system menu the timer started in a constructor is a really bad idea. The underlying native window (and menu) are created when the widget is first shown, so if the window is not shown immediately after it is created there might not yet be any system menu yet.

    The correct place to modify system menu is in response to WM_INITMENU message. You can implement a native event filter for example like this:

    bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
    {
        MSG* msg = (MSG*)message;
        if (msg->message == WM_INITMENU)
        {
            HMENU menu = (HMENU)msg->wParam;
            EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
        }
    
        return QMainWindow::nativeEvent(eventType, message, result);
    }
    


  • @Chris-Kawa

    The problem with setting window flags is that I'm intercepting the maximize command to simulate the window being maximized, so I need a way to enable the restore button while disabling the maximize button. In my experience it's been easier to just make the window appear as if it was maximized rather than deal with all the issues regarding the window state and size when dealing with frameless windows on multiple monitors (I'm doing a completely custom window).

    The timer was just a (in)sanity test to see if the EnableMenuItem() function worked at all, and I found in my case it only did when the menu was already open when the function was called. It seems like every time I open the system menu, it's creating a new one, because none of my changes are permanent; even when I call EnableMenuItem() outside of the constructor.

    I have a native event filter installed on the qApp instance, but I never receive the WM_INITMENU message.


Log in to reply