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

Center a QMainWindow on the current screen



  • Hi
    When starting a second QMainWindow from the main application QMainWindow, it is not centered on the screen, the position of the window is actually randomly placed on the screen.
    Also, In some cases I want to use saveGeometry() and restoreGeometry() to save what screen the window is on, and the size, but I want to center it on the screen.
    Is there a simpler way of centering the window on the current screeen?
    The following code works, but I think it could be done much better.
    The first if checks if the window is not placed on the first screen.
    The else if handles cases where it's on the first screen and the coordinates are not negative.
    The else handles cases for Windows where the coordinates are negative.

    // Make the window center on the current screen.
    
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
      QScreen *screen = QWidget::screen();
    #else
      QScreen *screen = (window() && window()->windowHandle() ? window()->windowHandle()->screen() : nullptr);
    #endif
    
    if (screen) {
      int pos_x = 0;
      if (x() > screen->availableGeometry().width()) {
        pos_x = (screen->availableGeometry().width() / 2) - (frameGeometry().width() / 2) + (screen->availableVirtualSize().width() - screen->availableGeometry().width());
      }
      else if (x() >= -100) {
        pos_x = (screen->availableGeometry().width() / 2) - (frameGeometry().width() / 2);
      }
      else {
        pos_x = -((screen->availableGeometry().width() / 2) + (frameGeometry().width() / 2));
      }
      int pos_y = 0;
      if (y() > screen->availableGeometry().height()) {
        pos_y = (screen->availableGeometry().height() / 2) - (frameGeometry().height() / 2) + (screen->availableVirtualSize().height() - screen->availableGeometry().height());
      }
      else if (y() >= -100) {
        pos_y = (screen->availableGeometry().height() / 2) - (frameGeometry().height() / 2);
      }
      else {
        pos_y = -((screen->availableGeometry().height() / 2) + (frameGeometry().height() / 2));
      }
      move(pos_x, pos_y);
    }
    

  • Moderators

    I don't think you need to do it case by case and the -100 should rather be calculated half of the window size. You should probably also make sure the window is not larger than the screen.

    Anyway, here's a little function that will do it:

    void center(QWidget& w, const QScreen& s)
    {
        const QRect sr = s.availableGeometry();
        const QRect wr({}, w.frameSize().boundedTo(sr.size()));
    
        w.resize(wr.size());
        w.move(sr.center() - wr.center());
    }
    


  • @Chris-Kawa
    This centers the window on the primary display instead of the current one.


  • Moderators

    @Jonas-Kvinge What do you mean by "current" screen? There's no such thing as far as I know.

    This centers it on whichever screen you pass it in the s param.
    You can make it the one where center of the window is, its corner, where the cursor is or whatever you want. You can use the code you already had for choosing a screen or you can use something like QGuiApplication::screenAt() to peek a different one.



  • @Chris-Kawa
    By current screen I'm talking about the screen where the program window is.
    For example I have two 1920x1080 monitors.
    move(0, 0) moves the window to the upper left corner of the primary screen.
    move(1920, 0) moves the window to the upper left corner of the second screen.
    Your code finds the center of availableGeometry() which always is the first screen.


  • Moderators

    @Jonas-Kvinge said:

    Your code finds the center of availableGeometry() which always is the first screen.

    It's not. It's the center of available geometry on given screen.
    For example I have two monitors: 1920x1080 and 1920x1200 and what I get is:

    Screen 1:
    Rect:             QRect(0,0 1920x1080)
    Available:        QRect(0,0 1920x1040)
    Available center: QPoint(959,519)
    
    Screen 2:
    Rect:             QRect(1920,0 1920x1200)
    Available:        QRect(1920,0 1920x1160)
    Available center: QPoint(2879,579)
    

    By current screen I'm talking about the screen where the program window is.

    Which point of that window? A window can span multiple screens.



  • @Chris-Kawa
    What I meant to write is when using the calculated availableGeometry() one specific screen and using the center of that in move, it will move to the coordinates of the whole desktop, meaning the primary screen in my case.

    Which point of the window? I guess the middle? If the window is placed partly on one screen and partly on the other it's not really important to me. What is important is that it can be centered on a different screen than the primary if the whole window is placed there.


  • Moderators

    @Jonas-Kvinge said:

    What I meant to write is when using the calculated availableGeometry() one specific screen and using the center of that in move, it will move to the coordinates of the whole desktop, meaning the primary screen in my case.

    Take a look at my numbers. availableGeometry() returns a rectangle in coordinates of the virtual desktop (a rectangle containing all screen geometries). If you use the second screen it's center is at (2879,578), which is on the second screen in the global coordinates. Moving a window there with move() will place it on that second screen.

    If your window is placed always on the primary screen you must be passing the wrong screen to that center() function I posted, because it works for any screen, not just the primary.



  • @Chris-Kawa Sorry, I see that now, your using QPoint().
    I see now that my problem is that QWidget::screen() is returning the same screen independent of what screen the QMainWindow is actually placed.



  • @Chris-Kawa said in Center a QMainWindow on the current screen:

    QGuiApplication::screenAt()

    Using QGuiApplication::screenAt() instead works.
    Solved now. Thanks!


Log in to reply