QML - main window position on start (screen center)

14,176

Solution 1

You'll need to setGeometry on your top-level widget before you show it. The easiest way I can think of to work out what geometry you need is via QDesktopWidget. Try the example below (create a QPushButton, press it while moving the widget around various screens) and you'll see what I mean:

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{   
  ui->setupUi(this);
  connect(ui->pushButton, SIGNAL(released()), this, SLOT(ButtonPressed()));
}

MainWindow::~MainWindow()
{
  delete ui;
}

void MainWindow::ButtonPressed()
{
  qDebug() << QApplication::desktop()->screenCount();
  qDebug() << QApplication::desktop()->screenNumber();
  qDebug() << QApplication::desktop()->screenGeometry(this);
}

Should be reasonably simple from there to come up with a generic version that works out a user's center screen (if it exists).

Solution 2

If using QtQuick, it's possible to do that:

import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0

ApplicationWindow {
    visible: true
    width: 320
    height: 480
    Component.onCompleted: {
        // Commenting this to use properties instead of setters
        //setX(Screen.width / 2 - width / 2);
        //setY(Screen.height / 2 - height / 2);
        x = Screen.width / 2 - width / 2
        y = Screen.height / 2 - height / 2
    }
}

Solution 3

Dielson's answer is much better, especially since widgets weren't mentioned... anyway, here's an even simpler version of his answer:

import QtQuick 2.0
import QtQuick.Window 2.0

Window {
    visible: true
    x: Screen.width / 2 - width / 2
    y: Screen.height / 2 - height / 2
    width: 320
    height: 480
}

As mentioned by Alexander, this binding can result in weird resizing behaviour. Because of that, it's better to use Dielson's answer. The only thing I'd mention is that it's not common to use setters in QML; some systems (I believe they're called property interceptors) even rely on properties being set to perform animations, for example. So the more common approach is as follows:

import QtQuick 2.0
import QtQuick.Window 2.0

Window {
    visible: true
    width: 320
    height: 480

    Component.onCompleted: {
        x = Screen.width / 2 - width / 2
        y = Screen.height / 2 - height / 2
    }
}

Solution 4

After examining both replies and actually debugging the code with Qt 5.9.1 it shows more than one issue with original replies:

  1. Cannot bind [x, y] to [width, height] unless we want to see strange effects with resizing.
  2. Even though [x, y] change in Component.onCompleted seems to be logical it does not work as expected with 2 monitors of different DPI (as on systems I currently develop on).
  3. Need to use Window.screen instead of Screen singleton type. That way we get actual screen matching the window on.
  4. To completely untie [x, y] from dynamic values but the actual window screen at the moment of the initial window showing we now use onScreenChanged which is a handler for the screen property change.

This solution is more complete and uses Window.screen property:

ApplicationWindow {
    id: window
    property bool screenInit: false

    title: qsTr("App Window Positioning")
    visible: true

    height: Theme.windowHeight // initial
    width: Theme.windowWidth   // initial

    Connections {
        target: window
        onScreenChanged: if (!screenInit) {
            // we have actual screen delivered here for the time when app starts
            screenInit = true
            window.x = screen.width / 2 - Theme.windowWidth / 2
            window.y = screen.height / 2 - Theme.windowHeight / 2
        }
    }
}

P.S. If so I used ApplicationWindow type which is derived from Window and it should be consistent with Window positioning behavior.

Solution 5

Alexander's answer is almost good enough. However, on KDE I observe the following behaviour: the window is first opened on Monitor 1 and then is immediately moved to Monitor 2. In this situation, the referenced answer always forces the window to Monitor 1.

Since trying to detect this behaviour would probably require quite a bit of code, I just went for a simple solution by using a Timer:

ApplicationWindow {
  id: window

  visible: true
  height: 320
  width: 480

  function setCoordinates() {
    x += screen.width / 2 - width / 2
    y += screen.height / 2 - height / 2
  }

  Timer {
    id: timer
    running: true
    repeat: false
    interval: 10
    onTriggered: {
      window.setCoordinates();
    }
  }
}

This sets the window's coordinates after waiting for 10ms (hopefully in that time the DE has done its job).

Share:
14,176
AntyaDev
Author by

AntyaDev

Updated on July 21, 2022

Comments

  • AntyaDev
    AntyaDev almost 2 years

    How I can do following: I’d like show my main window on start on the center screen.

  • Tomilov Anatoliy
    Tomilov Anatoliy about 6 years
    For ApplicationWindow there is a screen property.
  • JustWe
    JustWe about 6 years
    On the usability, this's the best answer for me. Upvoted
  • Alexander V
    Alexander V almost 6 years
    Either people cannot see that right away or they did not try? BTW, what about multi-monitor situation? The only correct way would be using screen property of Window then. doc.qt.io/qt-5/qml-qtquick-window-window.html#screen-prop
  • Mitch
    Mitch almost 6 years
    Not sure. It might have worked (resized without issues) back in 2014.
  • Alexander V
    Alexander V almost 6 years
    Absolutely sure and checked just yesterday on Ubuntu with 2 monitors of different dimensions. Depending on which monitor is main and has index 0 or Screen there is a bug of incorrect centering of the Window.
  • Mitch
    Mitch almost 6 years
    I said I'm not sure - I speak for myself. It's good that you're checking this stuff out, but I'm not accounting for multi-monitor setups in my answer, so feel free to provide your own.
  • Alexander V
    Alexander V almost 6 years
    Scratch that. Providing my reply as well.
  • Ignitor
    Ignitor over 3 years
    I tested this with Qt 5.15 on macOS but the onScreenChanged is not called when the window is initially shown. Only when the window is moved to another screen. Could be this changed somewhen..
  • Ignitor
    Ignitor over 3 years
    As mention in the comments of the other answer, one should rather use the screen property instead of the Screen singleton. Citing the documentation of the Screen type: "Note that the Screen type is not valid at Component.onCompleted, because the Item or Window has not been displayed on a screen by this time."