• Qt Quick 组件与动态对象


    博客24## 一、Components(组件)

    Component 是由 Qt 框架或开发者封装好的、只暴露了必要接口的 QML 类型,可以重复利用。一个 QML 组件就像一个黑盒子,它通过属性、信号、函数和外部世界交互。

    一个 Component 即可以定义在独立的 qml 文件中,也可以嵌入到其它的 qml 文档中来定义。通常我们可以根据这个原则来选择将一个 Component 定义在哪里:如果一个 Component 比较小且只在某个 qml 文档中使用或者一个 Component 从逻辑上看从属于某个 qml 文档,那就可以采用嵌入的方式来定义该 Component 。你也可以与 C++ 的嵌套类对比来理解。


    嵌入式定义组件

    示例 QML 代码如下:

    import QtQuick 2.0
    import QtQuick.Controls 1.1
     
    Rectangle {
         320;
        height: 240;
        color: "#C0C0C0";
        
        Text {
            id: coloredText;
            anchors.horizontalCenter: parent.horizontalCenter;
            anchors.top: parent.top;
            anchors.topMargin: 4;
            text: "Hello World!";
            font.pixelSize: 32;
        }
        
        Component {
            id: colorComponent;
            Rectangle {
                id: colorPicker;
                 50;
                height: 30;
                signal colorPicked(color clr);
                MouseArea {
                    anchors.fill: parent
                    onPressed: colorPicker.colorPicked(colorPicker.color);
                }
            }
        }
        
        Loader{
            id: redLoader;
            anchors.left: parent.left;
            anchors.leftMargin: 4;
            anchors.bottom: parent.bottom;
            anchors.bottomMargin: 4;
            sourceComponent: colorComponent;
            onLoaded:{
                item.color = "red";
            }
        }
        
        Loader{
            id: blueLoader;
            anchors.left: redLoader.right;
            anchors.leftMargin: 4;
            anchors.bottom: parent.bottom;
            anchors.bottomMargin: 4;
            sourceComponent: colorComponent;
            onLoaded:{
                item.color = "blue";
            }
        }
        
        Connections {
            target: redLoader.item;
            onColorPicked:{
                coloredText.color = clr;
            }
        }
        
        Connections {
            target: blueLoader.item;
            onColorPicked:{
                coloredText.color = clr;
            }
        }
    }
    

    如你所见,要在一个 QML 文档中嵌入 Component 的定义,需要使用 Component 对象。

    定义一个 Component 与定义一个 QML 文档类似, Component 只能包含一个顶层 item ,而且在这个 item 之外不能定义任何数据,除了 id 。比如上面的代码中,顶层 item 是 Rectangle 对象,在 Rectangle 之外我定义了 id 属性,其值为 colorComponent 。而顶层 item 之内,则可以包含更多的子元素来协同工作,最终形成一个具有特定功能的组件。

    Component 通常用来给一个 view 提供图形化组件,比如ListView::delegate属性就需要一个 Component 来指定如何显示列表的每一个项,又比如ButtonStyle::background属性也需要一个 Component 来指定如何绘制 Button 的背景。

    Component 不是 Item 的派生类,而是从 QQmlComponent 继承而来,虽然它通过自己的顶层 item 为其它的 view 提供可视化组件,但它本身是不可见元素。你可以这么理解:你定义的组件是一个新的类型,它必须被实例化以后才可能显示。而要实例化一个嵌入在 qml 文档中定义的组件,则可以通过 Loader。后面我们详细讲述 Loader ,这里先按下不表。


    二、使用 Loader

    2.1 Loader 的详细介绍

    Loader 用来动态加载 QML 组件。Loader 可以使用其 source 属性加载一个 qml 文档,也可以通过其 sourceComponent 属性加载一个 Component 对象。当你需要延迟一些对象直到真正需要才创建它们时, Loader 非常有用。

    当 Loader 的 source 或 sourceComponent 属性发生变化时,它之前加载的 Component 会自动销毁,新对象会被加载。将 source 设置为一个空字符串或将 sourceComponent 设置为 undefined ,将会销毁当前加载的对象,相关的资源也会被释放,而 Loader 对象则变成一个空对象。

    Loader 的 item 属性指向它加载的组件的顶层 item ,比如 Loader 加载了我们的颜色选择组件,其 item 属性就指向颜色选择组件的 Rectangle 对象。对于 Loader 加载的 item ,它暴露出来的接口,如属性、信号等,都可以通过 Loader 的 item 属性来访问。所以我们才可以这么使用:

    Loader{
    	id: redLoader;
    	anchors.left: parent.left;
    	anchors.leftMargin: 4;
    	anchors.bottom: parent.bottom;
    	anchors.bottomMargin: 4;
    	sourceComponent: colorComponent;
    	onLoaded:{
    		item.color = "red";
    	}
    }
    

    上面的代码在 Loader 对象使用 sourceComponent 属性来加载 id 为 colorComponent 的组件对象,然后在 onLoaded 信号处理器中使用 item 属性来设置颜色选择组件的颜色。对于信号的访问,我们则可以使用 Connections 对象,如下面的 qml 代码所示:

    Connections {
        target: redLoader.item;
        onColorPicked:{
            coloredText.color = clr;
        }
    }
    

    我们创建的 Connections 对象,其 target 指向 redLoader.item ,即指向颜色选择组件的顶层 item — Rectangle ,所以可以直接响应它的 colorPicked 信号。


    虽然 Loader 本身是 Item 的派生类,但没有加载 Component 的 Loader 对象是不可见的,没什么实际的意义。而一旦你加载了一个 Component , Loader 的大小、位置等属性却可以影响它所加载的 Component 。

    如果你没有显式指定 Loader 的大小,那么 Loader 会将自己的尺寸调整为与它加载的可见 item 的尺寸一致;如果 Loader 的大小通过 width 、 height 或 锚布局显式设置了,那么它加载的可见 item 的尺寸会被调整以便适应 Loader 的大小。不管是哪种情况, Loader 和它所加载的 item 具有相同的尺寸,这确保你使用锚来布局 Loader 就等同于布局它加载的 item 。


    2.2 从文件加载组件

    之前介绍 Loader 时,我们以嵌入式定义的 Component 为例子说明 Loader 的各种特性和用法,现在我们来看如何从文件加载组件。

    对于定义在一个独立文件中的 Component ,同样可以使用 Loader 来加载,只要指定 Loader 的 source 属性即可。现在再来修改下我们的例子,使用 Loader 来加载 ColorPicker 组件。

    示例代码如下:

    import QtQuick 2.0
    import QtQuick.Controls 1.1
     
    Rectangle {
         320;
        height: 240;
        color: "#EEEEEE";
        
        Text {
            id: coloredText;
            anchors.horizontalCenter: parent.horizontalCenter;
            anchors.top: parent.top;
            anchors.topMargin: 4;
            text: "Hello World!";
            font.pixelSize: 32;
        }
        
        Loader{
            id: redLoader;
             80;
            height: 60;
            focus: true;
            anchors.left: parent.left;
            anchors.leftMargin: 4;
            anchors.bottom: parent.bottom;
            anchors.bottomMargin: 4;
            source: "ColorPicker.qml";
            KeyNavigation.right: blueLoader;
            KeyNavigation.tab: blueLoader;
            
            onLoaded:{
                item.color = "red";
                item.focus = true;
            }
            
            onFocusChanged:{  
                item.focus = focus;
            }
        }
        
        Loader{
            id: blueLoader;
            focus: true;
            anchors.left: redLoader.right;
            anchors.leftMargin: 4;
            anchors.bottom: parent.bottom;
            anchors.bottomMargin: 4;
            source: "ColorPicker.qml";
            KeyNavigation.left: redLoader;
            KeyNavigation.tab: redLoader;
            
            onLoaded:{
                item.color = "blue";
            }
            
            onFocusChanged:{
                item.focus = focus;
            }  
        }
     
        Connections {
            target: redLoader.item;
            onColorPicked:{
                coloredText.color = clr;
                if(!redLoader.focus){
                    redLoader.focus = true;
                    blueLoader.focus = false;
                }
            }
        }
        
        Connections {
            target: blueLoader.item;
            onColorPicked:{
                coloredText.color = clr;
                if(!blueLoader.focus){
                    blueLoader.focus = true;
                    redLoader.focus = false;
                }
            }
        }
    }
    

    代码有几处改动:

    一处是将 sourceComponent 修改为 source ,其值为 "ColorPicker.qml" 。

    一处是两个 Connections 对象,在 onColorPicked 信号处理器中,设置了 Loader 的焦点属性,因为只有 Loader 有焦点,它加载的 item 才会有焦点,如果你鼠标点击某个颜色选择组件而加载它的 Loader 没有焦点,那么虽然颜色可以改变,但是焦点框出不来。

    使用 Loader 加载定义在 qml 文档中的组件,比直接使用组件名构造对象要繁琐得多,但如果你的应用会根据特定的情景来决定某些界面元素是否显示,这种方式也许可以满足你。


    参考:

    《Qt Quick核心编程》第7章

    Qt Quick 组件与对象动态创建详解


  • 相关阅读:
    5.线性回归算法
    4.K均值算法--应用
    3.K均值算法
    机器学习2
    机器学习1
    第十五次作业
    第十三次作业
    第十一次作业
    P1250 种树
    P1516 青蛙的约会
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/11938184.html
Copyright © 2020-2023  润新知