QML與C++:基于ListView調用外部模型進行增刪改查(附自定義組件)

目錄

    • 引言
    • 相關閱讀
    • 項目結構
      • 文件組織
    • 核心技術實現
      • 1. 數據模型設計
        • 聯系人項目類 (datamodel.h)
        • 數據模型類 (datamodel.h)
        • 數據模型實現 (datamodel.cpp)
      • 2. 主程序入口點 (main.cpp)
      • 3. 主界面設計 (Main.qml)
      • 4. 聯系人對話框 (ContactDialog.qml)
      • 5. 自定義組件
        • CustomTextField.qml
        • CustomButton.qml
        • IconButton.qml
    • 運行效果
    • 總結
    • 下載鏈接

引言

在上一篇中介紹了ListView的數據交互與樣式定制后,本文上一點強度,將通過一個聯系人管理的案例,詳細介紹如何使用QML與C++進行混合開發,充分展示QML的界面設計優勢和C++的數據處理能力。該應用基于ListView & Model實現了聯系人的增刪改查等基本功能,并通過自定義組件提升了用戶體驗。由于篇幅有限,會省略部分代碼,完整代碼請看本文最后的下載鏈接。

下一篇與ListView有關的文章,我將會進一步優化Model的性能。到時候在相關閱讀中補上鏈接。

相關閱讀

  • 接上篇 —— QML ListView:列表視圖的數據交互與樣式定制
  • 下篇 —— QML與C++:基于ListView調用外部模型進行增刪改查(性能優化版)

項目結構

以下是本項目的核心結構圖:

main.cpp
DataModel類
QML引擎
Main.qml
ContactDialog.qml
自定義組件
CustomTextField.qml
CustomButton.qml
IconButton.qml

文件組織

qml_listview_cpp/
├── CMakeLists.txt           # CMake構建配置
├── main.cpp                 # C++主函數
├── datamodel.h              # 數據模型頭文件
├── datamodel.cpp            # 數據模型實現
├── Main.qml                 # 主界面QML
├── ContactDialog.qml        # 聯系人對話框QML
├── components/              # 自定義組件目錄
│   ├── CustomTextField.qml  # 自定義文本輸入框
│   ├── CustomButton.qml     # 自定義按鈕
│   └── IconButton.qml       # 自定義圖標按鈕
├── icons/                   # 圖標資源目錄
│   ├── user.png             # 用戶圖標
│   ├── add.png              # 添加圖標
│   ├── delete.png           # 刪除圖標
│   ├── edit.png             # 編輯圖標
│   ├── find.png             # 搜索圖標
│   ├── phone.png            # 電話圖標
│   └── clear.png            # 清除圖標
└── image.qrc                # Qt資源文件

核心技術實現

1. 數據模型設計

本項目采用了QAbstractListModel作為基類創建自定義數據模型,實現了聯系人數據的管理。C++的數據模型為QML提供了高效的數據源。

聯系人項目類 (datamodel.h)
class ContactItem {
public:ContactItem(const QString &name, const QString &phone): m_name(name), m_phone(phone) {}QString name() const { return m_name; }QString phone() const { return m_phone; }QString firstLetter() const { return m_name.isEmpty() ? "?" : m_name.left(1).toUpper(); }private:QString m_name;QString m_phone;
};

ContactItem類定義了聯系人的基本屬性:姓名和電話。它還提供了一個便利方法firstLetter()用于獲取姓名的首字母,這將用于UI中的頭像顯示。

數據模型類 (datamodel.h)
class DataModel : public QAbstractListModel
{Q_OBJECTpublic:enum Roles {NameRole = Qt::UserRole + 1,PhoneRole,FirstLetterRole};explicit DataModel(QObject *parent = nullptr);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;// 暴露給QML的方法Q_INVOKABLE bool addContact(const QString &name, const QString &phone);Q_INVOKABLE bool removeContact(int index);Q_INVOKABLE bool editContact(int index, const QString &name, const QString &phone);Q_INVOKABLE QVariantList searchContacts(const QString &keyword);Q_INVOKABLE void clearSearch();private:QList<ContactItem> m_items;QList<ContactItem> m_originalItems; // 用于存儲搜索前的原始數據
};

DataModel類繼承自QAbstractListModel,實現了必要的虛函數:

  • rowCount(): 返回模型中的項目數量
  • data(): 根據索引和角色返回項目數據
  • roleNames(): 定義了模型中可用的角色名稱,這些名稱將在QML中使用

此外,還通過Q_INVOKABLE宏定義了幾個可以從QML中直接調用的方法:

  • addContact(): 添加聯系人
  • removeContact(): 刪除聯系人
  • editContact(): 編輯聯系人
  • searchContacts(): 搜索聯系人
  • clearSearch(): 清除搜索,恢復原始列表
數據模型實現 (datamodel.cpp)

數據模型的核心實現如下:

DataModel::DataModel(QObject *parent): QAbstractListModel(parent)
{// 添加一些示例聯系人數據m_items.append(ContactItem("張三", "13800138000"));m_items.append(ContactItem("李四", "13900139000"));m_items.append(ContactItem("王五", "13700137000"));// 保存原始數據m_originalItems = m_items;
}QVariant DataModel::data(const QModelIndex &index, int role) const
{if (!index.isValid())return QVariant();if (index.row() >= m_items.count())return QVariant();const ContactItem &item = m_items.at(index.row());switch (role) {case NameRole:return item.name();case PhoneRole:return item.phone();case FirstLetterRole:return item.firstLetter();default:return QVariant();}
}// 搜索聯系人實現
QVariantList DataModel::searchContacts(const QString &keyword)
{if (keyword.isEmpty()) {beginResetModel();m_items = m_originalItems;endResetModel();return QVariantList();}QVariantList results;beginResetModel();m_items.clear();for (const ContactItem &item : m_originalItems) {if (item.name().contains(keyword, Qt::CaseInsensitive) ||item.phone().contains(keyword, Qt::CaseInsensitive)) {m_items.append(item);}}endResetModel();return results;
}

2. 主程序入口點 (main.cpp)

主函數設置了QML引擎并將C++數據模型暴露給QML:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "datamodel.h"int main(int argc, char *argv[])
{QGuiApplication app(argc, argv);QQmlApplicationEngine engine;QObject::connect(&engine,&QQmlApplicationEngine::objectCreationFailed,&app,[]() { QCoreApplication::exit(-1); },Qt::QueuedConnection);// 創建數據模型實例DataModel *model = new DataModel(&engine);// 將模型暴露給QMLengine.rootContext()->setContextProperty("dataModel", model);engine.loadFromModule("qml_listview_cpp", "Main");return app.exec();
}

通過setContextProperty方法,將C++數據模型注冊為QML上下文屬性,這樣在QML代碼中就可以直接訪問dataModel對象了。

3. 主界面設計 (Main.qml)

主界面采用了QML編寫,實現了聯系人的列表顯示和搜索功能:

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import "./components"  // 導入自定義組件Window {width: 640height: 480visible: truetitle: "聯系人列表"// ... 省略部分代碼 ...ColumnLayout {anchors.fill: parentanchors.margins: 10spacing: 10// 頂部工具欄Rectangle {Layout.fillWidth: trueheight: 50color: "#f0f0f0"radius: 5RowLayout {anchors.fill: parentanchors.margins: 5spacing: 10CustomTextField {id: searchFieldLayout.fillWidth: trueplaceholderText: "搜索聯系人..."leftIcon: "qrc:/icons/find.png"onTextChanged: dataModel.searchContacts(text)onRightIconClicked: {text = ""dataModel.clearSearch()}}IconButton {text: "添加聯系人"iconSource: "qrc:/icons/add.png"showBackground: truebackgroundColor: "#BBDEFB"onClicked: addContactDialog.open()}}}// 聯系人列表ListView {Layout.fillWidth: trueLayout.fillHeight: truemodel: dataModelspacing: 10clip: truedelegate: Rectangle {width: ListView.view.widthheight: 80color: "#f0f0f0"radius: 5// ... 省略部分代碼 ...RowLayout {anchors.fill: parentanchors.margins: 10spacing: 15// 首字母頭像Rectangle {width: 60height: 60radius: width / 2color: {const colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEEAD", "#D4A5A5", "#9B59B6"]return colors[firstLetter.charCodeAt(0) % colors.length]}Text {anchors.centerIn: parenttext: firstLettercolor: "white"font.pixelSize: 24font.bold: true}}// 聯系人信息ColumnLayout {Layout.fillWidth: truespacing: 5Text {text: namefont.bold: truefont.pixelSize: 16Layout.fillWidth: true}Text {text: phonecolor: "#666666"font.pixelSize: 14Layout.fillWidth: true}}// 操作按鈕RowLayout {spacing: 10// 編輯按鈕IconButton {iconSource: "qrc:/icons/edit.png"onClicked: {currentEditIndex = indexeditContactDialog.currentName = nameeditContactDialog.currentPhone = phoneeditContactDialog.open()}}// 刪除按鈕IconButton {iconSource: "qrc:/icons/delete.png"onClicked: dataModel.removeContact(index)}}}}}}
}

主界面的核心部分是一個ListView,它使用C++提供的dataModel作為數據源。每個聯系人項目都顯示為一個帶有圓形首字母頭像、姓名、電話號碼以及編輯和刪除按鈕的矩形卡片。

主界面效果圖:

主界面效果圖


4. 聯系人對話框 (ContactDialog.qml)

為了添加和編輯聯系人,項目實現了一個模態對話框:

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "./components"Dialog {id: rootwidth: 400modal: true// 屬性property bool isEdit: false  // 用于區分是編輯還是添加模式property string currentName: ""property string currentPhone: ""// 標題根據模式動態設置title: isEdit ? "修改聯系人" : "添加新聯系人"closePolicy: Dialog.NoAutoClose// 信號signal contactConfirmed(string name, string phone)// ... 省略部分代碼 ...contentItem: ColumnLayout {spacing: 20anchors.margins: 10CustomTextField {id: nameFieldLayout.fillWidth: trueplaceholderText: "姓名"leftIcon: "qrc:/icons/user.png"}CustomTextField {id: phoneFieldLayout.fillWidth: trueplaceholderText: "電話"leftIcon: "qrc:/icons/phone.png"validator: RegularExpressionValidator {regularExpression: /^[0-9\+\-\s]*$/}}// 按鈕區域RowLayout {Layout.alignment: Qt.AlignRight | Qt.AlignBottomspacing: 10CustomButton {id: confirmButtontext: isEdit ? qsTr("保存") : qsTr("確定")enabled: nameField.text.length > 0 && phoneField.text.length > 0onClicked: root.accept()}CustomButton {id: cancelButtontext: qsTr("取消")bgColor: "#f5f5f5"textColor: "#333333"onClicked: root.reject()}}}
} 

這個對話框可以在兩種模式下工作:添加新聯系人和編輯現有聯系人。它包含兩個自定義文本輸入字段用于輸入姓名和電話號碼,以及確認和取消按鈕。

對話框效果圖:

添加聯系人

5. 自定義組件

為了提升UI的美觀度和復用性,項目定義了幾個自定義組件:

CustomTextField.qml

此處代碼省略…

這個自定義文本輸入框增強了標準的TextField,添加了左側圖標、右側圖標或清除按鈕等功能。如果所示:

自定義TextField


CustomButton.qml

此處代碼省略…

自定義按鈕組件提供了更靈活的外觀定制,包括背景色、文本色以及懸停效果。

主要在對話窗中使用了CustomButton:

自定義Button


IconButton.qml

此處代碼省略…

圖標按鈕組件實現了一個可以顯示圖標和文本的自定義按鈕,提供了豐富的自定義選項,如圖標大小、邊框、背景色等。

在列表中使用了IconButton:
IconButton1
在添加聯系人按鈕上使用了IconButton:
IconButton2

只需要設置背景色和文字即可實現不同的樣式效果。


運行效果

查找聯系人:

搜索

修改聯系人:

請添加圖片描述
新增/刪除聯系人:

新增和刪除


總結

本文介紹了一個基于Qt/QML與C++混合開發的聯系人管理應用。通過這個示例,我們展示了:

  1. QML與C++協同工作的模式:QML負責直觀高效的UI設計,C++處理數據邏輯和模型。
  2. 自定義QML組件的實現:通過組件化設計提高代碼復用性和可維護性。
  3. QAbstractListModel的使用:通過繼承QAbstractListModel創建自定義數據模型。
  4. 信號與槽機制:利用Qt的信號與槽機制實現UI與數據模型的解耦。

下載鏈接

您可以通過以下鏈接獲取完整的源代碼:GitCode -> QML -> ListView & Model

QML ListView & Model

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901869.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901869.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901869.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【MySQL】事務ACID理解記憶

事務的 ACID 特性詳解 數據庫中的 事務&#xff08;Transaction&#xff09; 是一組操作的集合&#xff0c;這些操作要么全部執行&#xff0c;要么全部不執行。為了保證事務可靠執行&#xff0c;必須滿足 ACID 四大特性&#xff1a; 特性英文縮寫簡要說明原子性Atomicity事務…

MYSQL “Too Many Connections“ 錯誤解決

1.查詢當前連接數 show status like "Threads_connected"; 2.查詢數據庫最大連接數 show variables like "max_connections" 3.查詢所有活動連接 show processlist; 4.根據查詢結果觀察是否有長時間未被釋放的連接 參數解釋 : 字段說明id連接的唯一…

Python爬蟲實戰:基于 Scrapy 框架的微博數據爬取研究

一、引言 1.1 研究背景 在當今數字化時代,社交媒體已成為信息傳播和公眾交流的重要平臺。微博作為國內極具影響力的社交媒體之一,每日產生海量的用戶生成內容,涵蓋新聞資訊、社交互動、娛樂八卦、熱點話題討論等多個領域。這些數據不僅反映了公眾的興趣偏好、情感態度和社…

貓咪如廁檢測與分類識別系統系列【九】視頻檢測區域在線繪制+支持攝像頭+網絡攝像頭+整體構建【上】

前情提要 家里養了三只貓咪&#xff0c;其中一只布偶貓經常出入廁所。但因為平時忙于學業&#xff0c;沒法時刻關注牠的行為。我知道貓咪的如廁頻率和時長與健康狀況密切相關&#xff0c;頻繁如廁可能是泌尿問題&#xff0c;停留過久也可能是便秘或不適。為了更科學地了解牠的如…

【AI插件開發】Notepad++ AI插件開發實踐:支持多平臺多模型

引言 上篇文章我們的Notepad插件介紹到Dock窗口集成&#xff0c;本篇將繼續完善插件功能&#xff0c;主要包括兩個部分&#xff1a; 支持多平臺、多模型支持多種授權驗證、接口類型 一、多平臺 原先的配置項很簡單&#xff1a; // PluginConf.h class PlatformConf { publ…

【C#】Socket通信的使用

在C#中&#xff0c;Socket通信是一種用于實現網絡通信的底層技術。通過Socket&#xff0c;程序可以在網絡上與其他設備進行數據交換。以下是如何使用C#中的System.Net.Sockets命名空間來實現Socket通信的詳細步驟。 1. Socket通信的基本概念 Socket: 一個Socket是網絡通信的端…

2024年第九屆團隊程序設計天梯賽c++題解L1-L3-1(附PTA網址)

L1-1 編程解決一切 5分 L1-097 編程解決一切 - 團體程序設計天梯賽-練習集 (pintia.cn)https://pintia.cn/problem-sets/994805046380707840/exam/problems/type/7?problemSetProblemId1781658570803388416 #include<bits/stdc.h> #define int long long using namesp…

ICMAN防水觸摸芯片 - 復雜環境下精準交互,提升觸控體驗

▍核心優勢 ◆ 超強抗干擾能力 ◆ 工業級設計&#xff0c;一致性和穩定性好 ▍提供場景化解決方案 【智能廚電矩陣】抽油煙機檔位調節 | 電磁爐火力觸控 | 洗碗機模式切換 【衛浴設備方案】淋浴房霧化玻璃控制 | 智能馬桶觸控面板 | 浴缸水位感應 【工業控制應用】儀器儀…

Golang|抽獎相關

文章目錄 抽獎核心算法生成抽獎大轉盤抽獎接口實現 抽獎核心算法 我們可以根據 單商品庫存量/總商品庫存量 得到每個商品被抽中的概率&#xff0c;可以想象這樣一條 0-1 的數軸&#xff0c;數軸上的每一段相當于一種商品&#xff0c;概率之和為1。 抽獎時&#xff0c;我們會生…

OpenCV 圖形API(43)顏色空間轉換-----將 BGR 圖像轉換為 LUV 色彩空間函數BGR2LUV()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 將圖像從BGR色彩空間轉換為LUV色彩空間。 該函數將輸入圖像從BGR色彩空間轉換為LUV。B、G和R通道值的傳統范圍是0到255。 輸出圖像必須是8位無符…

【Python】用Python寫一個俄羅斯方塊玩玩

【Python】用Python寫一個俄羅斯方塊玩玩 一、引言1.成品效果展示 二、思考準備1.思考設計2.代碼設計2.1 游戲頁面2.2 控件設計2.2.1 方塊生成2.2.2 方塊碰撞2.2.3 方塊消融2.2.4 游戲主循環2.2.5 游戲窗口 三、游戲完整版 一、引言 今日看到侄子在玩游戲&#xff0c;湊近一看…

維港首秀!沃飛長空AE200亮相香港特別行政區

4月13日-16日&#xff0c;第三屆香港國際創科展在香港會議展覽中心盛大舉辦。 作為國內領先、國際一流的eVTOL主機廠&#xff0c;沃飛長空攜旗下AE200批產構型登陸國際舞臺&#xff0c;以前瞻性的創新技術與商業化應用潛力&#xff0c;吸引了來自全球17個國家及地區的行業領袖…

Openfein實現遠程調用的方法(實操)

文章目錄 環境準備一、URL中接收參數二、接收一個參數三、接收多個參數四、傳遞對象五、傳遞JSON格式數據 環境準備 下面的配置&#xff0c;服務調用方加入即可。 依賴導入&#xff1a; <!-- openfeign依賴--><dependency><groupId>org.springframe…

Bright+Data網頁解鎖器:旅游行業數據革命的“隱形引擎”

在數字經濟浪潮中&#xff0c;旅游行業正經歷前所未有的變革。當消費者指尖滑動間完成跨國酒店預訂&#xff0c;當航空公司每秒調整萬次艙位價格&#xff0c;背后是一場無聲的數據戰爭。而在這場戰爭中&#xff0c;BrightData網頁解鎖器正成為旅游企業破局的關鍵武器——它像一…

OpenCV 圖形API(38)圖像濾波-----Sobel 算子操作函數Sobel()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 cv::gapi::Sobel 函數是 OpenCV 的 G-API 模塊中用于執行 Sobel 算子操作的一個函數&#xff0c;主要用于圖像的邊緣檢測。Sobel 算子通過計算圖…

CS5346 - Interactivity in Visualization 可視化中的交互

文章目錄 Visualization representation interactionInteraction &#xff08;交互&#xff09;Benefits (好處)Typical Interaction Techniques&#xff08;交互技術&#xff09;SelectFilteringAbstract / Elaborate幾何放縮&#xff08;Geometric zoom)語義放縮&#xff0…

第十六屆藍橋杯大賽軟件賽省賽 C++ 大學 B 組 部分題解

賽時參加的是Python組&#xff0c;這是賽后寫的題解&#xff0c;還有兩題暫時還不會&#xff0c;待更新 題目鏈接題目列表 - 洛谷 | 計算機科學教育新生態 A 移動距離 答案&#xff1a;1576 C 可分解的正整數 Python3 import itertools from functools import cmp_to_ke…

Vue 解決 Error: please transfer a valid prop path to form item!

在 Vue.js 中使用表單驗證庫&#xff08;如 VeeValidate 或 Element UI 的表單組件時&#xff09;&#xff0c;遇到錯誤信息 "please transfer a valid prop path to form item!" 通常指的是在表單項的屬性綁定中&#xff0c;路徑&#xff08;prop path&#xff09;不…

在 Visual Studio Code 中安裝通義靈碼 - 智能編碼助手

高效的編碼工具對于提升開發效率和代碼質量至關重要。 通義靈碼作為一款智能編碼助手&#xff0c;為開發者提供了全方位的支持。 本文將詳細介紹如何在 Visual Studio Code&#xff08;簡稱 VSCode&#xff09;中安裝通義靈碼&#xff0c;以及如何進行相關配置以開啟智能編碼…

SQL 解析 with as dual sysdate level

目錄 sql的運行順序 with as EXTRACT ?編輯 dual sysdate level ?編輯 ?編輯 Oracle中的日期存儲 核心部分 拆解字符串并計算最小值 關聯子查詢 NVL 函數 REGEXP_SUBSTR() sql的運行順序 <select id="getTrendList" parameterType="java.uti…