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,然后通过属性暴露的方式,进行绑定。又或者通过信号槽的方式发送过来。虽然还没有验证过,但应该是可以的。

相关推荐
youyou-06068 小时前
Classic AUTOSAR 中 CAN 协议栈整体架构
mcu·面试·汽车
神仙别闹8 小时前
基于 C++ 实现(控制台)学生成绩管理系统
开发语言·c++
会周易的程序员8 小时前
5 节点边缘冗余方案(上):基于 aiRaft 的物联网高可用控制面设计
c++·分布式·物联网·raft·iot·共识
此时不提桶,更待何时9 小时前
01-04-B-垃圾回收面试与生产事故实战
java·jvm·面试
伞伞悦读9 小时前
【第36期】Python 目录与路径详解:pathlib、文件遍历、创建、复制、移动和删除风险
开发语言·python
web守墓人11 小时前
【goed/ui】自定义组件设计思想篇
linux·windows·ui·golang
qq_1998868711 小时前
第6板块·第4节:构建系统与多文件项目
c++·人工智能·gpu算力
2601_9669496512 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
m0_7345717612 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
汉克老师13 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程