「Qt Widget中文示例指南」如何實現一個快捷編輯器(二)

Qt?是目前最先進、最完整的跨平臺C++開發工具。它不僅完全實現了一次編寫,所有平臺無差別運行,更提供了幾乎所有開發過程中需要用到的工具。如今,Qt已被運用于超過70個行業、數千家企業,支持數百萬設備及應用。

快捷編輯器示例展示了如何創建一個基本的讀寫層次模型,來與Qt的標準視圖和QKeySequenceEdit類一起使用。

點擊獲取Qt Widget組件下載(Q技術交流:166830288)

「Qt Widget中文示例指南」如何實現一個快捷編輯器

Qt的模型/視圖架構為視圖提供了一種標準的方式來操作數據源中的信息,使用數據的抽象模型來簡化和標準化訪問數據的方式。快捷編輯器模型將操作表示為項目樹,并允許視圖通過基于索引的系統訪問此數據。更一般地說,可以使用模型以樹結構的形式表示數據,方法是允許每個項作為子項表的父項。

在上文中(點擊這里回顧>>),我們為大家介紹了快捷編輯器的設計理念及結構等,本文將繼續介紹一些具體的實現類。

ShortcutEditorModel類實現

構造函數接受一個參數,其中包含模型將與視圖和委托共享的數據:

ShortcutEditorModel::ShortcutEditorModel(QObject *parent)
: QAbstractItemModel(parent)
{
m_rootItem = new ShortcutEditorModelItem({tr("Name"), tr("Shortcut")});
}

由構造函數來為模型創建根項,為方便起見,此項僅包含垂直標題數據。我們還使用它來引用包含模型數據的內部數據結構,并使用它來表示模型中頂級項的假想父項。

模型的內部數據結構由setupModelData()函數填充,我們將在本文末尾單獨研究這個函數。

析構函數確保在模型被銷毀時刪除根項及其所有子類:

ShortcutEditorModel::~ShortcutEditorModel()
{
delete m_rootItem;
}

由于在構造和設置模型之后我們不能向模型中添加數據,因此這簡化了管理內部項目樹的方式。

模型必須實現index()函數來為視圖和委托提供索引,以便在訪問數據時使用。當其他組件被它們的行號、列號以及它們的父模型索引引用時,為它們創建索引。如果將無效的模型索引指定為父索引,則由模型返回與模型中的頂級項對應的索引。

當提供模型索引時,我們首先檢查它是否有效。如果不是假定引用的是頂級項;否則我們使用模型索引的internalPointer()? 函數從模型索引中獲取數據指針,并使用它來引用TreeItem對象。注意我們構造的所有模型索引都將包含一個指向現有TreeItem的指針,因此可以保證接收到的任何有效模型索引都將包含一個有效的數據指針。

void ShortcutEditorModel::setActions()
{
beginResetModel();
setupModelData(m_rootItem);
endResetModel();
}

由于此函數的行和列參數引用相應父項的子項,因此我們使用TreeItem::child()函數獲得該項,createIndex()函數用于創建要返回的模型索引。我們指定行號和列號,以及指向項本身的指針,稍后可以使用模型索引來獲取項目的數據。

TreeItem對象的定義方式使得parent()函數的編寫變得簡單:

QModelIndex ShortcutEditorModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();ShortcutEditorModelItem *parentItem;
if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());ShortcutEditorModelItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);return QModelIndex();
}

我們只需要確保永遠不會返回與根項對應的模型索引,為了與index()函數的實現方式保持一致,我們為模型中任何頂級項的父項返回一個無效的模型索引。

當創建要返回的模型索引時,我們必須在父項中指定父項的行號和列號。我們可以很容易地使用TreeItem::row()函數發現行號,但是我們遵循指定0作為父列號的約定。模型索引是用createIndex()創建的,方法與index()函數相同。

rowCount()函數只是返回對應于給定模型索引的TreeItem的子條目的數量,或者如果指定了無效索引則返回頂級條目的數量:

QModelIndex ShortcutEditorModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();ShortcutEditorModelItem *childItem = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
ShortcutEditorModelItem *parentItem = childItem->parentItem();if (parentItem == m_rootItem)
return QModelIndex();return createIndex(parentItem->row(), 0, parentItem);
}

由于每個項目都管理自己的列數據,因此columnCount()函數必須調用項目自己的columnCount()函數來確定給定模型索引有多少列。與rowCount()函數一樣,如果指定了無效的模型索引,則返回的列數將從根項確定:

int ShortcutEditorModel::rowCount(const QModelIndex &parent) const
{
ShortcutEditorModelItem *parentItem;
if (parent.column() > 0)
return 0;if (!parent.isValid())
parentItem = m_rootItem;
else
parentItem = static_cast<ShortcutEditorModelItem*>(parent.internalPointer());return parentItem->childCount();
}

數據通過Data()從模型中獲得,由于項目管理它自己的列,我們需要使用列號來使用TreeItem::data()函數檢索數據:

int ShortcutEditorModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<ShortcutEditorModelItem*>(parent.internalPointer())->columnCount();return m_rootItem->columnCount();
}

注意,在這個實現中我們只支持DisplayRole,并且還為無效的模型索引返回無效的QVariant對象。

我們使用flags()函數來確保視圖知道模型是只讀的:

QVariant ShortcutEditorModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem*>(index.internalPointer());
return item->data(index.column());
}

headerData()函數返回我們方便地存儲在根項中的數據:

Qt::ItemFlags ShortcutEditorModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;Qt::ItemFlags modelFlags = QAbstractItemModel::flags(index);
if (index.column() == static_cast<int>(Column::Shortcut))
modelFlags |= Qt::ItemIsEditable;return modelFlags;
}

這些信息可以以不同的方式提供:在構造函數中指定,或者硬編碼到headerData()函數中。

QVariant ShortcutEditorModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return m_rootItem->data(section);
}return QVariant();
}

TODO

void ShortcutEditorModel::setupModelData(ShortcutEditorModelItem *parent)
{
ActionsMap actionsMap;
Application *application = static_cast<Application *>(QCoreApplication::instance());
ActionManager *actionManager = application->actionManager();
const QList<QAction *> registeredActions = actionManager->registeredActions();
for (QAction *action : registeredActions) {
QString context = actionManager->contextForAction(action);
QString category = actionManager->categoryForAction(action);
actionsMap[context][category].append(action);
}QAction *nullAction = nullptr;
const QString contextIdPrefix = "root";
// Go through each context, one context - many categories each iteration
for (const auto &contextLevel : actionsMap.keys()) {
ShortcutEditorModelItem *contextLevelItem = new ShortcutEditorModelItem({contextLevel, QVariant::fromValue(nullAction)}, parent);
parent->appendChild(contextLevelItem);// Go through each category, one category - many actions each iteration
for (const auto &categoryLevel : actionsMap[contextLevel].keys()) {
ShortcutEditorModelItem *categoryLevelItem = new ShortcutEditorModelItem({categoryLevel, QVariant::fromValue(nullAction)}, contextLevelItem);
contextLevelItem->appendChild(categoryLevelItem);
for (QAction *action : actionsMap[contextLevel][categoryLevel]) {
QString name = action->text();
if (name.isEmpty() || !action)
continue;ShortcutEditorModelItem *actionLevelItem = new ShortcutEditorModelItem({name, QVariant::fromValue(reinterpret_cast<void *>(action))}, categoryLevelItem);
categoryLevelItem->appendChild(actionLevelItem);
}
}
}
}

TODO

bool ShortcutEditorModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::EditRole && index.column() == static_cast<int>(Column::Shortcut)) {
QString keySequenceString = value.toString();
ShortcutEditorModelItem *item = static_cast<ShortcutEditorModelItem *>(index.internalPointer());
QAction *itemAction = item->action();
if (itemAction) {
if (keySequenceString == itemAction->shortcut().toString(QKeySequence::NativeText))
return true;
itemAction->setShortcut(keySequenceString);
}
Q_EMIT dataChanged(index, index);if (keySequenceString.isEmpty())
return true;
}return QAbstractItemModel::setData(index, value, role);
}

TODO

在模型中設置數據

我們使用setupModelData()函數在模型中設置初始數據,該函數檢索已注冊的操作文本并創建記錄數據和整體模型結構的項目對象。當然,這個函數的工作方式是非常特定于這個模型的。

為了確保模型正確工作,只需要創建具有正確數據和父項的ShortcutEditorModelItem實例。

Qt Widget組件推薦
  • QtitanRibbon?- Ribbon UI組件:是一款遵循Microsoft Ribbon UI Paradigm for Qt技術的Ribbon UI組件,QtitanRibbon致力于為Windows、Linux和Mac OS X提供功能完整的Ribbon組件。
  • QtitanChart?- Qt類圖表組件:是一個C ++庫,代表一組控件,這些控件使您可以快速地為應用程序提供漂亮而豐富的圖表。
  • QtitanDataGrid?- Qt網格組件:提供了一套完整的標準 QTableView 函數和傳統組件無法實現的獨特功能。使您能夠將不同來源的各類數據加載到一個快速、靈活且功能強大的可編輯網格中,支持排序、分組、報告、創建帶狀列、拖放按鈕和許多其他方便的功能。
  • QtitanDocking:允許您像 Visual Studio 一樣為您的偉大應用程序配備可停靠面板和可停靠工具欄。黑色、白色、藍色調色板完全支持 Visual Studio 2019 主題!

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

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

相關文章

Leetcode 第 129 場雙周賽題解

Leetcode 第 129 場雙周賽題解 Leetcode 第 129 場雙周賽題解題目1&#xff1a;3127. 構造相同顏色的正方形思路代碼復雜度分析 題目2&#xff1a;3128. 直角三角形思路代碼復雜度分析 題目3&#xff1a;3129. 找出所有穩定的二進制數組 I思路代碼復雜度分析 題目4&#xff1a;…

電子郵箱是什么?怎么申請一個電子郵箱?

電子郵箱是我們溝通的工具&#xff0c;細分為免費版電子郵箱和付費版電子郵箱。怎么申請一個屬于自己的電子郵箱&#xff1f;今天小編就分享一下電子郵箱注冊教程&#xff0c;手把手教您注冊一個電子郵箱。 一、電子郵箱的定義 電子郵箱&#xff0c;簡稱郵箱&#xff0c;是一…

BGP路由優選

1.BGP路由優選規則 上述規則依序排列&#xff0c;BGP進行路由優選時&#xff0c;從第一條規則開始執行&#xff0c;如果根據第一條規則無法作出判斷&#xff0c;例如路由的Preferred-Value屬性值相同&#xff0c;則繼續執行下一條規則&#xff0c;如果根據當前的規則&#xff0…

如何快速打開多個網頁?

在平常的工作當中&#xff0c; 如果每天都需固定打開幾個網站&#xff0c;可以通過創建一個批處理&#xff0c;一鍵打開需要的所有網站。 使用方法&#xff1a; 在桌面新建一個txt文本&#xff0c;按照以下格式輸入代碼&#xff0c;并將需要打開網站的地址輸入進去。 ? ec…

JavaScript異步編程——11-異常處理方案【萬字長文,感謝支持】

異常處理方案 在JS開發中&#xff0c;處理異常包括兩步&#xff1a;先拋出異常&#xff0c;然后捕獲異常。 為什么要做異常處理 異常處理非常重要&#xff0c;至少有以下幾個原因&#xff1a; 防止程序報錯甚至停止運行&#xff1a;當代碼執行過程中發生錯誤或異常時&#x…

虛擬化技術 在vCenter Server創建數中心、添加主機

一、實驗內容 1.安裝Flash 2.在vCenter Server創建數中心、添加主機 二、實驗主要儀器設備及器材 1.安裝有64位Windows操作系統的臺式電腦或筆記本電腦&#xff0c;建議4C8G或以上配置 2.在Windows Server 2008 R2已安裝vCenter Server 3.Adobe Flash Player 12.0.0.70.e…

算法-卡爾曼濾波之卡爾曼濾波的第一個方程:狀態更新方程

通過一個例子來引出卡爾曼濾波的狀態更新方程&#xff1b; 這里系統狀態是金條的重量&#xff1b; 為了估計系統的狀態&#xff0c;我們可以多次測量金條的重量&#xff0c;然后求平均值&#xff1b; 其中估計值是所有測量值的平均值&#xff1b; 由于我們使用的是靜態模型&am…

第十六節:圖 (20節)

一 圖的概念 1&#xff09;由點的集合和邊的集合構成 2&#xff09;雖然存在有向圖和無向圖的概念&#xff0c;但實際上都可以用有向圖來表達 3&#xff09;邊上可能帶有權值 二 圖結構的表達 1&#xff09;鄰接表法 2&#xff09;鄰接矩陣法 3&#xff09;除此之外還有其他眾多…

Halcon與深度學習框架結合進行圖像分析

Halcon 是一款強大的機器視覺軟件&#xff0c;而深度學習框架如 TensorFlow 或 PyTorch 在圖像識別和分類任務中表現出色。結合兩者的優勢&#xff0c;可以實現復雜的圖像分析任務。Halcon 負責圖像預處理和特征提取&#xff0c;而深度學習框架則利用這些特征進行高級分析和識別…

【完整過程】Windows下記錄PadleOCR訓練自己的ocr模型

一、前期準備 1、代碼 參考的博主使用的是2.6版本的 博主的paddleocr代碼 下面這個是官方的&#xff0c;可能已經更新了&#xff08;我用的是官網當前最新版&#xff09; paddleocr的源代碼 注意&#xff1a;最好把上面兩個代碼都下載下來&#xff0c;后面都會用到 參考博…

先有JVM還是先有垃圾回收器?

是先有垃圾回收器再有JVM呢&#xff0c;還是先有JVM再有垃圾回收器呢&#xff1f;或者是先有垃圾回收再有JVM呢&#xff1f;歷史上還真是垃圾回收更早面世&#xff0c;垃圾回收最早起源于1960年誕生的LISP語言&#xff0c;Java只是支持垃圾回收的其中一種。下面我們就來刨析刨析…

免費思維13招之十一:利潤型思維

免費思維13招之十一:利潤型思維 免費思維的另一大戰略思維——利潤型思維。 什么是利潤型思維呢?就是用后期的利潤來支付現在的成本。也就是“花未來的錢,辦現在的事”。 我們在銷售自己的產品時候,最容易犯的一個件事,就是降價,我們先來看一個案例: 前幾年,有一個賣…

React獲取form表單值的N種方式

Ref模式&#xff08;非受控模式&#xff09; 非鉤子模式 1.createRef()方式 js: userNameElcreateRef() <input type"text" name"userName" ref{this.userNameEl} /> 獲取值的方式&#xff1a; this.userNameEl.current.value2.refs(廢棄) js: con…

自動化圖像識別:提高效率和準確性的新途徑

自動化圖像識別是人工智能領域中的一項關鍵技術&#xff0c;它通過算法自動解析圖像內容&#xff0c;為各種應用提供準確的信息。隨著技術的不斷發展&#xff0c;自動化圖像識別在提高效率和準確性方面展現出新的途徑。 一、深度學習技術的應用 深度學習是自動化圖像識別領域…

3dmax材質庫導入方法?3dmax云渲染速度體驗

3ds Max 材質庫包含多種素材&#xff0c;如金屬、木材、布料和石材等&#xff0c;但用戶在導入材質時常遇到問題。本文將介紹如何在3ds Max中成功導入材質&#xff0c;并探討使用云渲染服務來加速渲染過程&#xff0c;提高項目效率。 一、3dmax材質庫導入教程 自建材質導入方法…

【js】獲取媒體流實現拍照功能,攝像頭切換

<script setup>import {onMounted,reactive,ref} from vueconst videoConstraints reactive({width: 500,height: 300});let picArr reactive([])let videoNode ref(null)let show ref(true)let stream reactive({})onMounted(async () > {// 獲取視頻流&#xf…

RuoYi-Vue-Plus (Logback 和 logback-plus.xml 、p6spy)

項目后本地日志 一、logback依賴 打開最外層的 pom.xml,查看 SpringBoot的依賴配置。 <dependencyManagement><dependencies><!-- SpringBoot的依賴配置--><dependency><groupId>org.springframework.boot</groupId><artifactId>s…

position:fixed無法固定到父盒子上面的解決方案

目錄 問題如圖所示&#xff1a; 下面是錯誤的代碼&#xff1a; 解決方案1&#xff1a; 使用fixed固定定位固定到父元素&#xff1a; 解決方案2&#xff1a; 推薦使用的其他方案&#xff08;粘性定位&#xff09;&#xff1a; 什么是粘性定位&#xff1a; 粘性定位的使用…

Leetcode—287. 尋找重復數【中等】(快慢指針算法)

2024每日刷題&#xff08;136&#xff09; Leetcode—287. 尋找重復數 快慢指針算法思想 low fast 時&#xff0c;快慢指針相遇&#xff0c;low 走過的距離是初始點&#xff08;0&#xff09;到環狀開始的點 &#xff08;x&#xff09; 加上 環狀開始的點&#xff08;x&…

LeetCode2390從字符串中移除星號

題目描述 給你一個包含若干星號 * 的字符串 s 。在一步操作中&#xff0c;你可以&#xff1a;選中 s 中的一個星號。移除星號 左側 最近的那個 非星號 字符&#xff0c;并移除該星號自身。返回移除 所有 星號之后的字符串。注意&#xff1a;生成的輸入保證總是可以執行題面中描…