输入关键词开始搜索

Qt QML 入门

最小 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 vs QWidget 选择

场景QMLQWidget
移动/嵌入式
传统桌面(表格/树/菜单)⚠️
动画/特效需自绘
学习曲线
性能(大量控件)