QML—启动时的主窗口位置(屏幕中心)

QML - main window position on start (screen center)

本文关键字:屏幕 位置 窗口 启动 QML      更新时间:2023-10-16

如何做到以下几点:我想在中央屏幕上显示启动时的主窗口。

如果使用QtQuick,可以做到这一点:

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
    }
}

Dielson的答案要好得多,尤其是因为没有提到小部件。。。不管怎样,这里有一个更简单的答案:

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
}

正如Alexander所提到的,这种绑定可能会导致奇怪的调整大小行为。正因为如此,最好使用Dielson的答案。我唯一要提到的是,在QML中使用setter并不常见;例如,一些系统(我相信它们被称为属性拦截器)甚至依赖于设置属性来执行动画。因此,更常见的方法如下:

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
    }
}

检查两个回复并使用Qt 5.9.1实际调试代码后,它显示原始回复存在多个问题:

  1. 无法将[x,y]绑定到[width,height],除非我们想看到调整大小的奇怪效果
  2. 尽管Component.onCompleted中的[x,y]变化似乎是合乎逻辑的,但对于两个不同DPI的监视器(就像我目前开发的系统一样),它并不能像预期的那样工作
  3. 需要使用Window.screen而不是Screen单例类型。这样我们就可以得到与窗口匹配的实际屏幕
  4. 为了从动态值中完全解开[x,y],但在显示初始窗口时的实际窗口屏幕,我们现在使用onScreenChanged,它是screen属性更改的处理程序

此解决方案更完整,并使用Window.screen属性:

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
        }
    }
}

附言:如果是这样的话,我使用了从Window派生的ApplicationWindow类型,它应该与Window的定位行为一致。

在显示顶级小部件之前,您需要在其上使用setGeometry。我能想到的最简单的方法是通过QDesktopWidget来计算您需要的几何图形。试试下面的例子(创建一个QPushButton,在各个屏幕上移动小部件时按下它),你就会明白我的意思:

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);
}

从那时起,应该相当简单地提出一个通用版本来处理用户的中心屏幕(如果存在的话)。

Alexander的回答几乎足够好了。然而,在KDE上,我观察到以下行为:窗口首先在监视器1上打开,然后立即移动到监视器2。在这种情况下,引用的答案总是将窗口强制设置为监视器1。

由于尝试检测这种行为可能需要相当多的代码,所以我只是使用计时器来寻找一个简单的解决方案:

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();
    }
  }
}

这将在等待10ms后设置窗口的坐标(希望在这段时间内DE已经完成了它的工作)。

所有其他答案都缺失,考虑到屏幕定位可能会导致窗口显示在错误的屏幕上。也许这在以前版本的Qt中曾经有效,但它似乎不再适用于最近的Qt版本。

以下解决方案适用于具有不同DPI设置的多屏幕(需要Qt 5.9或更高版本;在macOS上使用Qt 5.15进行测试):

import QtQuick 2.9
import QtQuick.Window 2.9
Window {
    id: root
    visible: true
    width: 320
    height: 480
    Component.onCompleted: {
        root.x = root.screen.virtualX + root.screen.width / 2 - root.width / 2;
        root.y = root.screen.virtualY + root.screen.height / 2 - root.height / 2;
    }
}