最小 QML 应用
// main.cpp — C++ 启动 QML
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl("qrc:/main.qml"));
return app.exec();
}
// main.qml
import QtQuick
Window {
width: 400; height: 300
visible: true
title: "Hello QML"
Text {
text: "Hello World"
anchors.centerIn: parent
font.pixelSize: 24
}
}
基础元素
// 布局容器
Rectangle { width: 100; height: 100; color: "lightblue"; radius: 8 }
Item { } // 不可见容器
Row { spacing: 10; /* 子元素水平排列 */ }
Column { spacing: 5; /* 垂直排列 */ }
Grid { columns: 3; spacing: 10 }
// 文本与输入
Text { text: "Label"; font.pixelSize: 16 }
TextInput { id: input; width: 200; text: "editable" }
TextEdit { width: 300; height: 200; text: "multiline" }
// 按钮
Button { text: "Click"; onClicked: console.log("clicked") }
// 图片
Image { source: "qrc:/icon.png"; width: 48; height: 48 }
属性绑定(核心概念)
Rectangle {
width: 200; height: 100
// 属性绑定 — 自动更新
color: mouseArea.containsMouse ? "red" : "blue"
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
Text {
// 绑定到表达式
text: "Width: " + parent.width
anchors.centerIn: parent
}
}
// 绑定是声明式的:color 自动跟随 mouseArea.containsMouse
信号与槽
Button {
id: myButton
text: "Click"
onClicked: {
console.log("clicked")
label.text = "Button was clicked"
}
}
// 属性变化信号
Item {
property int count: 0
onCountChanged: console.log("count:", count)
}
// 连接外部信号
Connections {
target: cppObject // C++ 暴露的对象
function onDataReady(data) {
chart.update(data)
}
}
C++ ↔ QML 交互
// ① 注册 C++ 类型到 QML
class DataProvider : public QObject {
Q_OBJECT
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
public:
QString status() const { return m_status; }
signals:
void statusChanged();
void dataReady(const QVariantList &data);
private:
QString m_status;
};
// main.cpp 中注册
qmlRegisterType<DataProvider>("myapp", 1, 0, "DataProvider");
// QML 中使用
import myapp 1.0
DataProvider {
id: provider
onDataReady: function(data) { /* ... */ }
}
// ② 从 C++ 访问 QML 对象
QObject *root = engine.rootObjects().first();
QObject *btn = root->findChild<QObject *>("myButton");
QMetaObject::invokeMethod(btn, "clicked");
布局锚定
Rectangle {
id: container
width: 400; height: 300
Rectangle {
anchors { // 用 anchors 而不是绝对坐标
left: parent.left; leftMargin: 10
right: parent.right; rightMargin: 10
top: parent.top; topMargin: 20
bottom: parent.bottom; bottomMargin: 20
}
}
// 居中
Text { anchors.centerIn: parent }
// 填充父容器
Item { anchors.fill: parent }
}
常用模式
// 列表(Repeater + model)
Column {
Repeater {
model: ["Alice", "Bob", "Carol"]
delegate: Text { text: modelData; font.pixelSize: 18 }
}
}
// 状态切换
Rectangle {
property bool active: false
color: active ? "green" : "gray"
states: [
State {
name: "active"; when: active
PropertyChanges { target: indicator; scale: 1.2 }
}
]
transitions: Transition {
NumberAnimation { property: "scale"; duration: 200 }
}
}
// 动画
Rectangle {
id: box
Behavior on x { NumberAnimation { duration: 300 } }
Behavior on opacity { NumberAnimation { duration: 200 } }
}
| 场景 | QML | QWidget |
|---|
| 移动/嵌入式 | ✅ | ❌ |
| 传统桌面(表格/树/菜单) | ⚠️ | ✅ |
| 动画/特效 | ✅ | 需自绘 |
| 学习曲线 | 中 | 低 |
| 性能(大量控件) | 中 | 高 |