【问题标题】:Saving window state with QML使用 QML 保存窗口状态
【发布时间】:2015-10-04 06:21:41
【问题描述】:

有没有一种很好的方法来记录 QtQuick 应用程序的窗口状态?文档给出了以下方法:

Settings {
    property alias x: mainWindow.x
    property alias y: mainWindow.y
    property alias width: mainWindow.width
    property alias height: mainWindow.height

但是这有三个缺陷:

  1. 当您调整/移动窗口时,它会不断写入设置文件。
  2. 它不记得窗口是否最大化(顺便说一句,Notepad++ 也有这个烦人的缺陷)。
  3. 如果最大化窗口,它不会保存未最大化的几何图形。

谁有更好的代码?

【问题讨论】:

标签: qt window qml settings qtquick2


【解决方案1】:

就我有限的测试显示而言,我设法制作了一些效果很好的东西。我确实不得不做一个 hacky 位,因为不幸的是 Window.visibilityWindow.x/y/width/height 之后更新,这意味着如果您尝试记录 windowed 几何图形,您不能只检查状态Window.visibility 中的 onXChanged。相反,我必须记录前两个值,然后在窗口最大化时丢弃最近的一个。

编辑:这并不完美。如果最大化窗口,则关闭应用程序。然后打开它,然后再次关闭它。然后再次打开它,当您取消最大化时,它不会回到正确的窗口大小。我认为修复这将是丑陋的 QML,我可能会在它真正所属的 C++ 中实现它。

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
import Qt.labs.settings 1.0

Item {
    property Window window

    // Default properties for the application's first run.
    property int defaultX: 100
    property int defaultY: 100
    property int defaultWidth: 500
    property int defaultHeight: 500
    property bool defaultMaximised: false

    Settings {
        id: windowStateSettings
        category: "WindowState"
        property int x
        property int y
        property int width
        property int height
        property bool maximised
    }

    Component.onCompleted: {
        if (windowStateSettings.width === 0 || windowStateSettings.height === 0)
        {
            // First run, or width/height are screwed up.
            curX = defaultX;
            curY = defaultY;
            curWidth = defaultWidth;
            curHeight = defaultHeight;
            curMaximised = defaultMaximised
        }
        else
        {
            curX = windowStateSettings.x;
            curY = windowStateSettings.y;
            curWidth = windowStateSettings.width;
            curHeight = windowStateSettings.height;
            curMaximised = windowStateSettings.maximised
        }
        window.x = prevX = curX;
        window.y = prevY = curY;
        window.width = prevWidth = curWidth;
        window.height = prevHeight = curHeight;

        if (curMaximised)
            window.visibility = Window.Maximized;
    }

    // Remember the windowed geometry, and whether it is maximised or not.
    // Internal use only.
    property int curX
    property int curY
    property int curWidth
    property int curHeight
    property bool curMaximised

    // We also have to save the previous values of X/Y/Width/Height so they can be restored if we maximise, since we
    // can't tell that the updated X,Y values are because of maximisation until *after* the maximisation.
    property int prevX
    property int prevY
    property int prevWidth
    property int prevHeight

    Connections {
        target: window
        onVisibilityChanged: {
            if (window.visibility === Window.Maximized)
            {
                curMaximised = true;
                // Ignore the latest X/Y/width/height values.
                curX = prevX;
                curY = prevY;
                curWidth = prevWidth;
                curHeight = prevHeight;
            }
            else if (window.visibility === Window.Windowed)
            {
                curMaximised = false;
            }
            else if (window.visibility === Window.Hidden)
            {
                // Save settings.
                windowStateSettings.x = curX;
                windowStateSettings.y = curY;
                windowStateSettings.width = curWidth;
                windowStateSettings.height = curHeight;
                windowStateSettings.maximised = curMaximised;
            }
        }

        // We can't use window.visibility here to ignore the maximised geometry because it changes after the geometry.
        // Instead we cache the two previous values and revert them if maximised.
        onXChanged: {
            prevX = curX;
            curX = window.x;
        }
        onYChanged: {
            prevY = curY;
            curY = window.y;
        }
        onWidthChanged: {
            prevWidth = curWidth;
            curWidth = window.width;
        }
        onHeightChanged: {
            prevHeight = curHeight;
            curHeight = window.height;
        }
    }

}

像这样使用它:

ApplicationWindow {
    id: mainWindow

    WindowStateSaver {
        window: mainWindow
        defaultWidth: 1000 // Or whatever. You can also specify the defaultX/Y if you want.
        defaultHeight: 700
    }

【讨论】:

  • 嗨,非常感谢!我知道如何在 C++ 中做到这一点,但我在 QML 中努力实现同样的目标!我还修复了您在编辑中提到的情况:保存设置时,您需要检查 curMaximised 状态:如果它是真的,那么您需要保存以前的状态,否则是当前状态。当可见性变为窗口时,我也会更新所有状态,但我不知道是否有必要。
  • 如果我关闭外接显示器上的窗口,然后拔下显示器并重新启动应用程序,Windows 会发生什么情况?我的猜测是它仍然会在外接显示器上打开应用程序,因此用户将无法访问它。
  • 我正在使用 Qt 6。我认为他们已经改变了行为。能见度似乎在 x/y/w/h 之前更新。我在 C++ 中管理设置。 x/y/w/h 使用 Binding 更新,isMaximizedonVisibilityChanged 处理程序中更新。 IsMaximized 总是首先更新,所以我可以使用它来知道不存储其他设置。
【解决方案2】:

基于 Timmmm 的回答,但可能更适合。

import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.3
import Qt.labs.settings 1.0

Item
{
    property Window window
    property string windowName: ""

    Settings
    {
        id: s
        category: windowName
        property int x
        property int y
        property int width
        property int height
        property int visibility
    }

    Component.onCompleted:
    {
        if (s.width && s.height)
        {
            window.x = s.x;
            window.y = s.y;
            window.width = s.width;
            window.height = s.height;
            window.visibility = s.visibility;
        }
    }

    Connections
    {
        target: window
        onXChanged: saveSettingsTimer.restart()
        onYChanged: saveSettingsTimer.restart()
        onWidthChanged: saveSettingsTimer.restart()
        onHeightChanged: saveSettingsTimer.restart()
        onVisibilityChanged: saveSettingsTimer.restart()
    }

    Timer
    {
        id: saveSettingsTimer
        interval: 1000
        repeat: false
        onTriggered: saveSettings()
    }

    function saveSettings()
    {
        switch(window.visibility)
        {
        case ApplicationWindow.Windowed:
            s.x = window.x;
            s.y = window.y;
            s.width = window.width;
            s.height = window.height;
            s.visibility = window.visibility;
            break;
        case ApplicationWindow.FullScreen:
            s.visibility = window.visibility;
            break;
        case ApplicationWindow.Maximized:
            s.visibility = window.visibility;
            break;
        }
    }
}

用法。像这样的:

ApplicationWindow 
{
    id: mainWindow
    WindowStateSaver 
    {
        window: mainWindow
        windowName: "mainWindow"
    }
}

【讨论】:

    猜你喜欢
    • 2022-11-15
    • 2017-05-06
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多