QML面试常见问题(一)QML中组件呈现方式的方法有哪些

前言

本文主要想要记录面试时可能会被问到的一些qml常见问题,帮助面试前快速复习和回顾。

由于是记录文章,所以会不断往后添加问题,必要时会另开新文章。

一、QML中组件呈现方式的方法有哪些?

1.基础属性绑定(最直接的 UI 数据呈现)

这是 QML 的基石。无论是 QML 内部的 property 还是从 C++ 暴露过来的对象属性,只要把 UI 组件的属性(如 text)和它进行绑定,数据一变,界面自动刷新。

cpp 复制代码
import QtQuick
import QtQuick.Controls

Window {
    width: 400; height: 200; visible: true
    title: "基础属性绑定"

    // 1. 在 QML 内部定义属性变量
    property string statusText: "等待操作..."
    property int clickCount: 0

    Column {
        anchors.centerIn: parent
        spacing: 20
        // 2. 直接将属性绑定到组件上
        Label { text: statusText; font.pixelSize: 20 }
        
        Button {
            text: "点击我"
            onClicked: {
                clickCount++
                // 修改属性,界面上的 Label 会自动更新
                statusText = "按钮已被点击 " + clickCount + " 次"
            }
        }
    }
}

注:如果是 C++ 交互,你只需要把 statusText 换成从 C++ 注册进来的单例对象属性(如 cppBackend.statusText)即可,绑定语法完全一致。

2.绑定C++侧对象属性

这部分是上述方法的补充,详情可以回看之前学习记录的博客文章。

核心思想是将C++元素暴露给qml侧,让它能够进行调用。这里主要分为几种思路。
(1)上下文属性暴露

通过以下接口,我们可以将某个属性暴露给qml侧。

cpp 复制代码
QString lastName = "Doe";
QString firstName = "John";

engine.rootContext()->setContextProperty("lastname", QVariant::fromValue(lastName));
engine.rootContext()->setContextProperty("firstname", QVariant::fromValue(firstName));

可以看到,这种方式并没有创建什么c++实例对象,单纯只是将一个变量注册暴露给qml。另外,传参的名字类似别名,可以和原变量名不一样。

但上下文属性暴露同样支持暴露实例对象,

cpp 复制代码
CppClass1 cppclass1;
engine.rootContext()->setContextProperty("CppClass1",&cppclass1);

这种方法也是给类实例对象取别名,其公共接口使用Q_INVOKABLE 修饰后,可在qml中直接被调用。而信号不需要修饰也可以用。

重点来了,如果需要使用其变量,我们需要先在头文件声明中,对某个成员变量进行Q_PROPERTY属性声明。

这里的成员变量和Q_PROPERTY声明的属性,本质上不是绑定关系,是因为我们在该属性的具体方法(读写、通知)中调用了成员变量,故形成了绑定关系。此后,在qml中调用该属性,就相当于绑定了成员变量。如:text: xxx.name

(2)上下文对象暴露

和上述的方法类似,但这种方法暴露实例对象的时候,不需要取别名,qml使用的时候没有名字修饰,直接引用属性(变量)名(需要Q_PROPERTY修饰),这看上去比较精简方便,但有命名冲突的风险。

个人不推荐这种方式,如果需要单例,我们可以使用qmlRegisterSingletonInstance的方式
(3)单例

略。详情看博客文章。

3.信号槽

qml中同样支持信号槽的方式。

如果想要在qml中呈现数据,可以在qml中接收某个c++对象的信号。

方法大概如下,首先,我们需要对c++某个实例对象进行属性暴露,然后在qml中Connections中实现槽函数。具体实现类似如下:

cpp 复制代码
    Connections{
        target: CppSignalSender

        onCallQml: function(parameter){
            console.log("This is QML: callQml signal cought:")
            mText.text = parameter
        }

        onCppTimer: function(value){
            mRectText.text = value
        }
    }

4.ListView中呈现数据

由于面试官问到过这个,我就记录一下。(相关笔记55-57)

实际上,在qml中,这是比较典型的model-view结构,还涉及到delegate的概念。

我不想过多展开,简单来说,view即视图层的组件,即listview,model是数据来源,而delegate则是委托,它比较抽象,除了决定ui样式,还可以决定数据的表现方式。

比如model的一项数据(listelement)里面有name和price两个属性,而delegate可以决定呈现方式为rectangle里内嵌一个文本,文本绑定了:name+"---"+price。这是相当灵活的表现形式。

listview对应的就是listmodel,有关model的定义形式比较丰富,较为正式的是这种,ListElement是其中一个元素:

cpp 复制代码
 ListModel{
        id: modelId
        ListElement{
            country:"China"
            capital: "BeiJing"
        }
        ListElement{
        // ...
        }
    }

还有就是这种内联定义的方式:

cpp 复制代码
model: ["January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"]

方式有很多,但这种方式的数据来源都是qml。

如果想要从c++侧获取数据来源,可以在那边定义model,然后通过属性暴露的方式,进行绑定。又或者通过信号槽的方式发送过来。虽然还没有验证过,但应该是可以的。

相关推荐
Aurorar0rua1 小时前
CS50 x 2024 Notes C -12
c语言·开发语言·学习方法
techdashen1 小时前
深入 Rust enum 的内存世界
开发语言·后端·rust
knight_9___2 小时前
大模型project面试7
人工智能·python·算法·面试·大模型·agent
yuhuofei20212 小时前
【Python入门】Python与PyCharm的安装
开发语言·python·pycharm
吴声子夜歌2 小时前
Java——类加载机制
java·开发语言·python
杨校2 小时前
杨校老师课堂之C++的位运算应用专项训练
开发语言·c++
笨蛋不要掉眼泪2 小时前
Java并发编程:线程的创建和运行
java·开发语言·jvm
九伯都2 小时前
java编写 agent 入门案例
java·开发语言
j7~2 小时前
【MYSQL】在Centos7和ubuntu22.04环境下安装
数据库·c++·mysql·ubuntu·centos