QML - 主窗口启动时的位置(屏幕中央)

11

我该如何做以下操作:我想在启动时将我的主窗口显示在屏幕中心。

6个回答

30

如果使用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
    }
}

在可用性方面,这对我来说是最好的答案。已点赞。 - JustWe
1
正如另一个答案的评论中所提到的,应该使用screen属性而不是Screen单例。引用Screen类型的文档:“请注意,在Component.onCompleted时,Screen类型无效,因为此时尚未在屏幕上显示ItemWindow。” - Ignitor

24

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

1
对于ApplicationWindow,有一个screen属性。 - Tomilov Anatoliy
1
人们可能无法立即看到,或者他们没有尝试过?顺便问一下,多显示器的情况怎么样?那么唯一正确的方法就是使用 Windowscreen 属性。http://doc.qt.io/qt-5/qml-qtquick-window-window.html#screen-prop - Alexander V
不确定。在2014年可能可以正常工作(调整大小没有问题)。 - Mitch
1
绝对确定,昨天在Ubuntu上检查过,使用了两个不同尺寸的显示器。根据哪个显示器是主显示器并具有索引0或屏幕,存在一个窗口居中不正确的错误。 - Alexander V
我说我不确定 - 我只代表我自己。你能够检查这些东西是很好的,但是我的回答并没有考虑多显示器设置,所以请随意提供你自己的解决方案。 - Mitch
取消那个。我也提供我的回复。 - Alexander V

3

在检查了原始回复并实际调试了Qt 5.9.1代码后,发现以下问题:

  1. 如果不想看到奇怪的尺寸变化效果,就不能将 [x, y] 绑定到 [width, height]。
  2. 尽管在 Component.onCompleted 中更改 [x, y] 似乎是合理的,但在具有不同DPI的2个显示器上却没有按预期工作(如我目前开发的系统)。
  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的定位行为保持一致。


我在macOS上使用Qt 5.15进行了测试,但是当窗口最初显示时,onScreenChanged没有被调用。只有当窗口移动到另一个屏幕时才会被调用。可能会在某个时候更改这种情况。 - Ignitor

1

在展示顶层widget前,您需要setGeometry。我能想到的最简单的方法来确定所需的几何图形是通过QDesktopWidget。尝试下面的例子(创建一个QPushButton,同时移动widget到各个屏幕上),然后您就会明白我的意思:

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

从那里开始,应该相对简单地设计出一个通用版本,以确定用户的中心屏幕(如果存在)。


1

亚历山大的回答几乎已经足够好了。然而,在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();
    }
  }
}

这将在等待10毫秒后设置窗口的坐标(希望在此期间DE已经完成了其工作)。

1
所有其他答案都没有考虑屏幕定位的因素,可能导致窗口显示在错误的屏幕上。也许这在早期版本的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;
    }
}

这对我来说是正确的答案。在 Windows 11 上使用 Qt 6.4.2 也可以正常工作 :) - Foaly
这对我来说是正确的答案。在Windows 11上,使用Qt 6.4.2也可以正常工作 :) - Foaly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接