Home > Blockchain >  Qt - Keep menu within parent window
Qt - Keep menu within parent window

Time:12-28

I am trying to display a relatively simple QMenu that is shown when the user pressed a button. It looks something like this:

menu overflowing the mainwindow

The menu has a fixed width and the trigger button is located at the end of a horizontal layout, which looks something along the lines of :

**AppMainWindow** (QDialog with flags Qt::WindowCloseButtonHint | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint)
--> **Header** (QWidget with a QHBoxLayout)
--> **DropDownMenu** (QToolButton)
--> **QMenu**

My problem, as you can see, is that the menu overflows the main window. It seems like if it doesn't have enough room within the screen, it will have the desired effect of opening within the main window towards the left rather than overflowing on the right:

menu correctly tucked-in

Note that this was done on the edge of the screen, however a second screen was present where it could have been expanded, similarly to what is happening on the first screenshot.

This is the relevant code of the DropDownMenu class in the constructor:

setPopupMode(QToolButton::ToolButtonPopupMode::InstantPopup);
_menu = new Menu(this);
_menu->setWindowFlags(_menu->windowFlags() | Qt::Tool | Qt::FramelessWindowHint);
_menu->setAttribute(Qt::WA_TranslucentBackground);
setMenu(_menu);

The Menu class is simply an override of the QMenu in order to have show/hide animations.

I have tried changing the window flags/attributes of the menu to various values (Qt::SubWindow, Qt::Dialog, Qt::Popup, Qt::WA_LayoutOnEntireRect...) without seeing any interesting results. How would you go about forcing the opening of the menu from within the parent window? I would ideally like to avoid redefining the opening position of the menu (via an updateGeometry() or paintEvent()), and would expect this behaviour to be available natively with Qt, but cannot find out how to do so.

CodePudding user response:

I solved it by overriding setVisible on the menu and moving it upon opening if it is about to open outside the parent window.

void Menu::setVisible(bool visible) {
   if (visible) {
      if (parentWidget() != nullptr) {
         // If it is about to open outside of the parent window,
         // replace it to fit within the parent window
         const QRect& appWindow = parentWidget()->window()->geometry();
         const int windowMaxX = appWindow.right();
         const QPoint menuTopLeft = pos();
         const QSize menuSize = sizeHint();
         if (windowMaxX < menuTopLeft.x()   menuSize.width()) {
            move(QPoint(windowMaxX - menuSize.width(), menuTopLeft.y()));
         }
      }    
   }

   // Do extra stuff if needed here
   Super::setVisible(visible);
}
  • Related