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

               

    在《Qt Quick 事件处理之信号与槽》一文中介绍自定义信号时,举了一个简单的例子,定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Connections 对象连接到组件的 colorPicked 信号,改变文本的颜色。 当时用到的 Component 、 Loader 两个特性,一直没来得及介绍,可能很多人都还在雾里看花呢。这次呢,我们就来仔仔细细地把他们讲清楚。

    版权所有 foruok ,转载请注明出处:http://blog.csdn.net/foruok

Components(组件)

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

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

嵌入式定义组件

    《Qt Quick 事件处理之信号与槽》一文中使用到 Component 的示例 QML 代码如下:

import QtQuick 2.0import QtQuick.Controls 1.1Rectangle {    width: 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;            width: 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;        }    }}

    其中,颜色选择组件的定义代码如下:

    Component {        id: colorComponent;        Rectangle {            id: colorPicker;            width: 50;            height: 30;            signal colorPicked(color clr);            MouseArea {                anchors.fill: parent                onPressed: colorPicker.colorPicked(colorPicker.color);            }        }    }

    如你所见,要在一个 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 ,这里先按下不表,我们要来看如何在一个文件中定义组件了。

在单独文件中定义组件

    很多时候我们把一个 Component 单独定义在一个 qml 文档中,比如 Qt Quick 提供的 BusyIndicator 控件,其实就是在 BusyIndicator.qml 中定义的一个组件。下面是 BusyIndicator.qml 文件的内容:

Control {    id: indicator    property bool running: true    Accessible.role: Accessible.Indicator    Accessible.name: "busy"    style: Qt.createComponent(Settings.style + "/BusyIndicatorStyle.qml", indicator)}

    我在《 Qt Quick 简单教程》一文中的显示网络图片实例中,使用了 BusyIndicator 来提示用户图片正在加载中需要等候,你可以跳转到那篇文章学习 BusyIndicator 的用法。

    BusyIndicator 组件的代码非常简单,只是给 Control 元素(Qt Quick 定义的私有元素,用作其它控件的基类,如 ComboBox 、 BusyIndicator 等)增加了一个属性、设置了几个属性的值,仅此而已。

    不知你是否注意到了, BusyIndicator.qml 文件中的顶层 item 是 Control ,而我们使用时却是以 BusyIndicator 为组件名(类名)。这是我们定义 Component 时要遵守的一个约定:组件名字必须和 qml 文件名一致。好嘛,和 Java 一样啦,类名就是文件名。还有一点,组件名字的第一个字母必须是大写。对于在文件中定义一个组件,就这么简单了,再没有其它的特殊要求。 Qt Quick 提供的多数基本元素和特性,你都可以在定义组件时使用。

    一旦你在文件中定义了一个组件,就可以像使用标准 Qt Quick 元素一样使用你的组件。比如我们给颜色选择组件起个名字叫 ColorPicker ,对应的 qml 文件为  ColorPicker.qml ,那么你就可以在其它 QML 文档中使用 ColorPicker {...} 来定义 ColorPicker 的实例。

    好啦,现在让我们来看看在单独文件中定义的 ColorPicker 组件:

import QtQuick 2.0import QtQuick.Controls 1.1Rectangle {    id: colorPicker;    width: 50;    height: 30;    signal colorPicked(color clr);        function configureBorder(){        colorPicker.border.width = colorPicker.focus ? 2 : 0;          colorPicker.border.color = colorPicker.focus ? "#90D750" : "#808080";     }        MouseArea {        anchors.fill: parent        onClicked: {            colorPicker.colorPicked(colorPicker.color);            mouse.accepted = true;            colorPicker.focus = true;        }    }    Keys.onReturnPressed: {        colorPicker.colorPicked(colorPicker.color);        event.accepted = true;    }    Keys.onSpacePressed: {        colorPicker.colorPicked(colorPicker.color);        event.accepted = true;    }        onFocusChanged: {        configureBorder();    }        Component.onCompleted: {        configureBorder();    }}

    请注意上面的代码,它和嵌入式定义有明显不同: Component 对象不见咧!对,就是酱紫滴:在单独文件内定义组件,不需要 Component 对象,只有在其它 QML 文档中嵌入式定义组件时才需要 Component 对象。另外,为了能够让多个 ColorPicker 组件可以正常的显示焦点框,我还使用了 onClicked 信号处理器,新增了 onFocusChanged 信号处理器,在它们的实现中调用 configureBorder() 函数来重新设置边框的宽度和颜色,新增 onReturnPressed 和 onSpacePressed 以便响应回车和空格两个按键。

    你可以使用 Item 或其派生类作为组件的根 item 。 ColorPicker 组件使用 Rectangle 作为根 Item 。现在让我们看看如实在其它文件中使用新定义的 ColorPicker 组件。我修改了上节的示例,新的 qml 文件被我命名为 component_file.qml ,内容如下:

import QtQuick 2.0import QtQuick.Controls 1.1Rectangle {    width: 320;    height: 240;    color: "#EEEEEE";        Text {        id: coloredText;        anchors.horizontalCenter: parent.horizontalCenter;        anchors.top: parent.top;        anchors.topMargin: 4;        text: "Hello World!";        font.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值