qt - 具有代码控制属性的组件(无默认值)

标签 qt qml qtquick2

摘要

如何在 QML 中创建一个组件,允许我指定具有默认值的自定义属性,这些属性可以被命令行参数覆盖,但最初不使用默认值?

背景

我创建了一个 QML 组件,可用于轻松解析命令行属性并绑定(bind)到它们的值。它的用法如下所示:

Window {
    visibility: appArgs.fullscreen ? "FullScreen"  : "Windowed"
    width: appArgs.width
    height: width*9/16

    CommandLineArguments {
        id: appArgs

        property real width: Screen.width
        property bool fullscreen: false

        Component.onCompleted: args(
          ['width',      ['-w', '--width'],      'initial window width'],
          ['fullscreen', ['-f', '--fullscreen'], 'use full-screen mode']
        )
    }
}
$ ./myapp --help
qml: Command-line arguments supported:
-w, --width        : initial window width    (default:1920)
-f, --fullscreen   : use full-screen mode    (default:false)

它工作得很好,除了......

问题

为我的组件创建的所有绑定(bind)最初都使用默认值。例如,如果我使用 -w 800 启动应用程序,则窗口的 width 最初以 1920 的值开始,然后立即调整大小为 800(当 Component.onCompleted 代码运行)。这个问题在 90% 的情况下是不明显的,在 8% 的情况下有点烦人……在最后 2% 的情况下无法使用。

有时我想要控制的属性只能设置一次。例如,使用脆弱代码连接的网络端口在更改时无法断开连接并重新连接到新端口。或者一个映射库,它为一种视觉样式加载大量资源,然后在我尝试更改样式时抛出错误。

因此,我需要这些属性来在第一次创建它们时获取命令行值(如果指定)(否则使用默认值)。我怎样才能做到这一点?

最佳答案

更新:实际上,在这种特殊情况下,实际上很容易避免调整大小 - 只需将可见性设置为 false,然后将属性设置为所需的值,并将可见性设置为 true:

Window {
  id: main
  visible: false

  Component.onCompleted: {
    main.width = ARG_Width // replace with 
    main.height = ARG_Width * 9/16 // your stuff
    main.visibility = ARG_Fullscreen ? Window.FullScreen : Window.Windowed
    main.visible = true
  }
}

在这种情况下,这很方便,因为您可以简单地隐藏窗口,直到设置所需的属性值。如果您确实需要创建具有正确初始值的组件,您可以执行以下操作:

Item {
  id: main
  Component {
    id: win
    Window {
      visible: true
      width: ARG_Width
      height: width*9/16
      visibility: ARG_Fullscreen ? Window.FullScreen : Window.Windowed
    }
  }

  Component.onCompleted: win.createObject(main)
}

在这种情况下,应用程序将在没有任何窗口的情况下启动,所需的值将在原型(prototype)级别设置,以便其创建将被延迟并从一开始就具有正确的值。


发生这种情况是可以理解的,毕竟您在应用程序加载之前才读取参数。因此它将加载默认值,然后切换到提供的参数。

如果您想避免这种情况,最直接的解决方案是在加载主 qml 文件之前读取参数并将它们公开为上下文属性,例如(发布完整的工作代码,因为您提到您不是C++ 人):

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
  QGuiApplication app(argc, argv);
  QQmlApplicationEngine engine;

  int w = 1920; // initial
  bool f = false; // values

  QStringList args = app.arguments();
  if (args.size() > 1) { // we have arguments
    QString a1 = args.at(1);
    if (a1 == "-w") w = args.at(2).toInt(); // we have a -w, read in the value
    else if (a1 == "-f") f = true; // we have a -f
  }
  engine.rootContext()->setContextProperty("ARG_Width", w); // expose as context 
  engine.rootContext()->setContextProperty("ARG_Fullscreen", f); // properties

  engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); // load main qml

  return app.exec();
}

然后在您的 main.qml 文件中:

Window {
  id: main
  visible: true
  width: ARG_Width
  height: width*9/16
  visibility: ARG_Fullscreen ? Window.FullScreen : Window.Windowed
}

创建组件后,它会立即获取正确的值。

关于qt - 具有代码控制属性的组件(无默认值),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41231658/

相关文章:

qt - 使用原始 OpenGL 调用绘制 Qml 项的问题

c++ - 与 Qt 第三方库的静态链接

c++ - Qt - 无法分配给不存在的属性(自定义 C++ 类)

qt - 调整窗口大小时文本变得模糊

qt - 升级到 qt 5.5.0 后,我收到了 QML 导入的警告

android - 为 TableView 中的新项目设置动画

linux - 如何使用应用程序部署 Qt 库?

qt - qmake -query 返回旧的 Qt 安装

c++ - 如何在点击 Qtablewidget 单元格时获取放置在该单元格中的小部件的行号?

qt - 如何在 QML 5.14 中使用 Markdown 格式