美文网首页Qt QML/Quck编程
QML中使用全局变量

QML中使用全局变量

作者: 吉米有态度 | 来源:发表于2018-03-25 15:42 被阅读0次

全局变量,顾名思义就是在程序中到处都能使用的变量。这在一定程度上违背了“模块化设计”这个思想。在笔者刚接触编程的时候老师就说过全局变量有害,就跟goto一样;但在实际工程中它其实很有用,使用得当的话反而能让整个软件结构更清晰、紧凑。本文结合实际经验向大家介绍在QML程序中如何有效使用全局变量。

全局变量的作用

首先要说明的是,我们这里说的全局变量不是整数、浮点数这样的简单变量,而是复杂的类对象。那什么时候会用到全局变量呢?在笔者的实践中,一般下面几种情况会用到全局变量:

  1. 资源共享、重用。整个应用程序相关的设置,比如说程序的版本、风格(theme)、字体资源等,这些数据适合放入一个全局变量,从而可以在整个程序的任何地方反复使用;
  2. 数据传递。全局变量在代码里都能访问到,相当于一块共享的内存空间,所以可以在不同的地方传递数据。但如果是多线程环境下的话,需要考虑好互斥;
  3. 事件驱动。我们可以将该变量申明为QObject子类,然后定义好信号与槽,然后在程序需要的地方连接这些信号或者调用槽函数,这样我们的程序就通过这个全局变量连接起来了。这就相当于有了一个核心驱动,比如只要一个信号发出来,程序中所有连接的槽函数就都会被调用,而无需关心是否漏掉了一个。

这几个特点加起来其实也就是Facebook所推崇的Flux设计模块,核心思想简单讲就是把程序的层级关系变得简单,单一驱动。如果你被综错复杂的模块化设计弄糊涂了,那可以试试Flux这种清晰明了的设计思路。

和C++中的使用全局变量相比,QML中使用起来更加方便,因为QML中有属性绑定,尤其是上面第三点,确实可以让我们的程序“智能化”很多。同时也要说明的是,这里说的“全局”并不是真的全局,而是指QML执行环境中的全局;C++中的全局变量不在本文讨论范围之内。

QML中定义全局变量

我们知道QML是需要QML引擎(即QQmlEngine)来解释执行的,所以QML中的全局变量本质是QML执行上下文(QQmlContext)的属性。定义QML全局变量也就是把我们的对象设置为QML执行上下文的属性。

有两种方式:单独定义,或者批量定义,其中批量定义又可分为C++形式和QML形式。我们把这些方法都介绍下。

单独定义

该方法主要步骤是:

  1. 定义一个QObject的子类,设计好它的信号、槽还有属性;

  2. main函数里构建对象;

  3. QQmlEngine构建之后还未加载任何QML文件之前,将该对象设置为执行上下文的属性,并取一个合理的名字:

    engine->rootContext()->setContextProperty("$hub", cppBackend);
    

这样$hub就成为了QML中的全局变量,你可以直接使用它内部的各种元数据(信号、槽、属性、枚举类型等等)。

这里我们约定,用$作为全局变量的开头字母,这个在JavaScript和QML中是合法的,便于我们区分普通局部变量和全局变量。

C++形式批量定义

如果我们的程序比较复杂,把功能都放在一个全局变量里不合适,我们可以将它们拆开来,用不同的C++类来实现,然后定义一个总的C++类,将这些功能类作为这个总类的属性,主要步骤是:

  1. 根据功能定义不同类,例如:
    程序设置类:

    class Settings : public QObject{
        Q_OBJECT
    public:
        Q_PROPERTY(QString appName MEMBER m_appName)
    private:
        QString m_appName = "MyApp";
    }
    

    和网络类:

    class Networks : public QObject{
        Q_OBJECT
    }
    
  2. 定义一个总的类:

    class GlobalObject : public QObject{
        Q_OBJECT
    public:
        Q_PROPERTY(Settings* settings MEMBER m_settings)
        Q_PROPERTY(Networks* networks MEMBER m_networks)
    private:
        Settings* m_settings;
        Networks* m_networks;
    }
    
  3. main函数中创建总类的对象:

    auto globalObject = new GlobalObject();
    
  4. QQmlEngine构建之后还未加载任何QML文件之前,将该对象设置为执行上下文对象:

    engine->rootContext()->setContextObject(globalObject);
    

QML中约定,contextObject的所有属性都自动变为contextProperty,就像他们用第一种方法单独定义一样。所以如果需要的功能比较多,建议使用批量定义的方法,更方便快捷。

需要注意,如果一个程序中同时使用了这两种方法定义全局变量而且有变量重名了,那么以单独定义的优先。

QML形式批量定义

可以用QML文件来代替上面的C++总类。

在定义好SettingsNetworks之后,接下去的步骤改为:

  1. 将这些C++类注册到QML中:

    qmlRegisterType<Settings>("MyCppBackend", 1, 0, "Settings");
    qmlRegisterType<Networks>("MyCppBackend", 1, 0, "Networks");
    
  2. 然后新建一个QML文件:

    //globalobject.qml
    import QtQuick 2.7
    import MyCppBackend 1.0
    
    QtObject {
        id: root
        property var $settings: Settings{}
        property var $networks: Networks{}
    }
    
  3. 将该QML文件作为QML引擎加载的第一个文件:

    engine->load(QUrl("qrc:///globalobject.qml")); 
    

QML引擎约定,加载的第一个QML文件就是contextObject,所以和C++定义类似,它的属性也就成了contextProperty

和C++批量定义相比,QML批量定义有如下优势:

  • 变量名前面可以加$,从而方便区分全局变量和局部变量,这个在C++定义属性的时候是不允许的;

  • 如果某个全局变量(一般是QML对象)构造很慢,可以通过QML中的Loader来很方便异步构造,从而加速程序启动:

    property var loader: Loader{
        asynchronous: true
        source: "qrc:/UI/Main.qml"
        onLoaded: {
            // 当加载完毕会进入这里
        }
    }
    

QML全局变量的中枢作用

最后我们结合批量定义中的例子来看下QML中全局变量起的数据、消息中枢作用。这个主要是利用了QML的属性绑定特性(Property Binding)。

假如说我们有两个QML文件:

//View1
import QtQuick 2.7
Item{
    id: root
    Text{
        text: $settings.appName
    }
}

和:

//View2
import QtQuick 2.7
import QtQuick.Controls 2.2
Rectangle{
    id: root
    TextField{
        text: $settings.appName
    }
    Button{
        text: "Click!"
        onClick:{
            $settings.appName = "New Name!";
        }
    }
}

View1View2中的text都和$settings中的appName这个属性做了绑定。当我点击View2中的按钮,$settings.appName被修改,所有绑定的属性也就会自动更新,不会遗忘。由于$settings是全局变量,这种用法可以深入到任意复杂、任意层级的界面中,非常方便。

相关文章

  • qml全局变量定义建议

    从C++导入到qml的全局变量和qml定义变量或许有些混淆,使用下列建议或许可以解决全局变量混淆的问题。   定义...

  • QML中使用全局变量

    全局变量,顾名思义就是在程序中到处都能使用的变量。这在一定程度上违背了“模块化设计”这个思想。在笔者刚接触编程的时...

  • 官方提供的基础指南一

    1.Hello World 程序 2.QML 实现GUI界面 QML 使用声明式语法实现GUI界面,要使用QML实...

  • QmlLoader

    qml中可以使用Loader来加载并显示qml文件 调用 就可以加载对应的qml文件并显示了 需要完整代码请访问Q...

  • QML Canvas基础概念

    阅读本文大概需要3分钟 QML中绘图方式有多种,Canvas(QML)是一种,当然使用QQuickPaintedI...

  • QML Loader 使用注意事项

    QML 的 Loader 元素经常被用来动态加载 QML 组件。可以使用 source 属性或者 sourceCo...

  • QWidget 调用 QML 插件中的对象

    目标 为实现从QML字符串中创建QML对象,并显示在基于QWidget项目工程中,且这个QML对象所属类型来自QM...

  • QML中文件的加载

    在这里小小总结一下QML文件中如何加载QML文件与JavaScript文件。 1、QML文件中加载JavaScri...

  • QtQuick/Qml自定义控件(9)-Quick组件管理

    Qml开发中经常需要使用大量的动态创建的对象, 并且需要进行管理. qml可以通过Qt.createCompone...

  • Vue全局变量的实现方式

    创建js文件,添加需要使用的全局变量 1、全局变量模块导入方式 2、全局变量挂载到Vue.ptototype中

网友评论

    本文标题:QML中使用全局变量

    本文链接:https://www.haomeiwen.com/subject/kgohcftx.html