這是最簡單的方式,可以在QML中直接繫結C++ 物件的屬性。通過在C++ 物件中使用Q_PROPERTY宏定義屬性,然後在QML中使用繫結語法將屬性與QML元素關聯起來。
person.h
#include <QObject>
class Person : public QObject
{
Q_OBJECT
/* 使用 Q_PROPERTY 定義互動的屬性 */
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
public:
explicit Person(QObject *parent = nullptr)
: QObject(parent), m_name(""), m_age(0)
{
}
/* 為屬性提供 getter 和 setter 方法 */
QString getName() const { return m_name; }
void setName(const QString& name) { m_name = name; emit nameChanged(); }
int getAge() const { return m_age; }
void setAge(int age) { m_age = age; emit ageChanged(); }
signals:
/* 訊號與屬性對應,通過訊號通知其他物件屬性的變化 */
void nameChanged();
void ageChanged();
private:
QString m_name;
int m_age;
};
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "person.h"
int main(int argc, char *argv[])
{
/* 啟用Qt應用程式的高DPI縮放功能 */
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
/* 建立一個Qt應用程式的範例 */
QGuiApplication app(argc, argv);
// 建立Person物件
Person person;
QQmlApplicationEngine engine;
/* 將Person物件作為QML上下文屬性 */
engine.rootContext()->setContextProperty("person", &person);
const QUrl url(QStringLiteral("qrc:/main.qml"));
/* 將 QQmlApplicationEngine 物件的 objectCreated 訊號連線到一個 lambda 函數上 */
/* lambda 函數用於在 QML 檔案中的根物件被建立時進行處理,檢查物件是否成功建立,如果建立失敗則退出應用程式 */
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
/* 載入QML檔案並顯示使用者介面 */
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
visible: true
width: 480
height: 800
title: qsTr("Hello World")
Column {
spacing: 10
TextField {
placeholderText: "請輸入姓名"
text: person.name // 與Person物件的name屬性繫結
onTextChanged: person.name = text // 當文字改變時,更新Person物件的name屬性
}
Slider {
from: 0
to: 100
value: person.age // 與Person物件的age屬性繫結
onValueChanged: person.age = value // 當滾軸值改變時,更新Person物件的age屬性
}
Text {
text: "姓名:" + person.name
}
Text {
text: "年齡:" + person.age
}
}
}
C++ 物件可以發出訊號,而QML中的元素可以連線到這些訊號上。這樣,當C++ 物件的狀態發生變化時,可以通過訊號與槽機制將這些變化傳遞給QML介面。
myobject.h
#include <QObject>
#include <QtDebug>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
signals:
void mySignal(QString message);
public slots:
void mySlot(const QString& message) { qDebug() << "Received message from QML:" << message; emit mySignal("Hello from C++");}
};
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myobject.h"
int main(int argc, char *argv[])
{
/* 啟用Qt應用程式的高DPI縮放功能 */
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
/* 建立一個Qt應用程式的範例 */
QGuiApplication app(argc, argv);
/* 將自定義 C++ 型別註冊到 QML 中的函數, 將自定義 C++ 型別註冊到 QML 中的函數 */
qmlRegisterType<MyObject>("com.example", 1, 0, "MyObject");
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
/* 將 QQmlApplicationEngine 物件的 objectCreated 訊號連線到一個 lambda 函數上 */
/* lambda 函數用於在 QML 檔案中的根物件被建立時進行處理,檢查物件是否成功建立,如果建立失敗則退出應用程式 */
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
/* 載入QML檔案並顯示使用者介面 */
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import com.example 1.0
Window {
visible: true
width: 480
height: 800
title: qsTr("Hello World")
/* 定義 sendToCpp 訊號 */
signal sendToCpp(string message)
/* Connections 元件用於連線 myObject 的 onMySignal 訊號 */
Connections {
target: myObject
onMySignal: console.log("Received message from C++:", message)
}
MyObject {
id: myObject
/* 將 onMySignal 訊號傳遞到 sendToCpp訊號上,便於 QML 處理 */
onMySignal: sendToCpp(message)
}
Button {
text: "Send message to C++"
anchors.centerIn: parent
/* 單擊按鈕時,會將訊號傳遞到 C++ 的 mySlot 槽上 */
onClicked: myObject.mySlot("Hello from QML")
}
}
模型檢視(Model-View):可以使用C++ 中的資料模型(QStandardItemModel)來提供資料給QML介面。QML中的檢視元素(如ListView或GridView)可以使用這些模型來顯示資料。
mymodel.h
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QAbstractListModel>
#include <QList>
class MyModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit MyModel(QObject *parent = nullptr);
enum {
NameRole = Qt::UserRole + 1,
AgeRole,
EmailRole
};
// 重寫以下幾個虛擬函式
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
private:
struct Person {
QString name;
int age;
QString email;
};
QList<Person> m_persons;
};
#endif // MYMODEL_H
mymodel.cpp
#include "mymodel.h"
MyModel::MyModel(QObject *parent)
: QAbstractListModel(parent)
{
// 初始化一些資料
m_persons.append({"Alice", 25, "[email protected]"});
m_persons.append({"Bob", 30, "[email protected]"});
m_persons.append({"Charlie", 35, "[email protected]"});
}
int MyModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_persons.count();
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= m_persons.count() || index.row() < 0)
return QVariant();
const Person &person = m_persons[index.row()];
if (role == NameRole)
return person.name;
else if (role == AgeRole)
return person.age;
else if (role == EmailRole)
return person.email;
return QVariant();
}
QHash<int, QByteArray> MyModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[AgeRole] = "age";
roles[EmailRole] = "email";
return roles;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "mymodel.h"
int main(int argc, char *argv[])
{
/* 啟用Qt應用程式的高DPI縮放功能 */
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
/* 建立一個Qt應用程式的範例 */
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyModel myModel;
engine.rootContext()->setContextProperty("myModel", &myModel);
const QUrl url(QStringLiteral("qrc:/main.qml"));
/* 將 QQmlApplicationEngine 物件的 objectCreated 訊號連線到一個 lambda 函數上 */
/* lambda 函數用於在 QML 檔案中的根物件被建立時進行處理,檢查物件是否成功建立,如果建立失敗則退出應用程式 */
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
/* 載入QML檔案並顯示使用者介面 */
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
visible: true
width: 480
height: 800
title: qsTr("Hello World")
ListView {
anchors.fill: parent
model: myModel
delegate: Item {
width: parent.width
height: 60
Column {
Text { text: name }
Text { text: age }
Text { text: email }
}
}
}
}
執行效果
QML型別註冊(QML Type Registration):可以將C++ 物件註冊為自定義的QML型別,使得QML可以直接建立和使用這些物件。通過在C++ 中使用 Q_PROPERTY 宏和 Q_INVOKABLE 函數,可以將C++ 類註冊為QML型別。我需要這樣一個案例
myobject.h
#include <QQmlEngine>
#include "QDebug"
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:
explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}
QString name() const { return m_name; }
void setName(const QString &name) { m_name = name; emit nameChanged(); }
Q_INVOKABLE void printName() { qDebug() << "Name:" << m_name; }
static void registerQmlType()
{
qmlRegisterType<MyObject>("com.example", 1, 0, "MyObject");
}
signals:
void nameChanged();
private:
QString m_name;
};
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "myobject.h"
int main(int argc, char *argv[])
{
/* 啟用Qt應用程式的高DPI縮放功能 */
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
/* 建立一個Qt應用程式的範例 */
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyObject::registerQmlType();
const QUrl url(QStringLiteral("qrc:/main.qml"));
/* 將 QQmlApplicationEngine 物件的 objectCreated 訊號連線到一個 lambda 函數上 */
/* lambda 函數用於在 QML 檔案中的根物件被建立時進行處理,檢查物件是否成功建立,如果建立失敗則退出應用程式 */
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
/* 載入QML檔案並顯示使用者介面 */
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import com.example 1.0
Window {
visible: true
width: 480
height: 800
title: qsTr("Hello World")
MyObject {
id: myObject
name: "John"
}
/* 垂直佈置元件 */
Column {
anchors.fill: parent // 大小為父元件的大小
anchors.margins: 40 // 與父元件四周的間隔
spacing: 10 // 子元件之間的間隔
Text {
text: myObject.name
}
Button {
text: "Print Name"
onClicked: myObject.printName()
}
}
}
本文來自部落格園,作者:澆築菜鳥,轉載請註明原文連結:https://www.cnblogs.com/jzcn/p/17774676.html
如本部落格的內容侵犯了你的權益,請與以下地址聯絡,本人獲知後,馬上刪除。同時本人深表歉意,並致以崇高的謝意! [email protected]