博客地址已更改,文章數量較多不便批量修改,若想訪問源文請到 coologic博客 查閱,網址:www.coologic.cn
如本文記錄地址為 techieliang.com/A/B/C/ 請改為 www.coologic.cn/A/B/C/ 即可查閱
版權聲明:若無來源注明, Techie亮博客文章均為原創。 轉載請以鏈接形式標明本文標題和地址:
本文標題:QTreeView/QTableView中利用QStandardItem實現復選框三種形態變化 本文地址: http://techieliang.com/2017/12/729/
1. 介紹
復選框有三種形態:全選對勾、全不選空白、半選黑點
在item中通過:setCheckable(true);可開啟復選框功能,但默認只支持全選對勾、全不選空白,而且自身的狀態變動不會使父/子節點相應,比如子節點全部選中時父節點不會自動勾選
下面你提供一個完整的UsingCheckboxItem類,此類繼承自QStandardItem,實現了復選框三種狀態的使用。類內容很純粹並未增加其他設置,僅為復選框實現。
注意,此方式讓一個item調用了其父節點及子節點的data和setdata兩個方法,若不符合設計要求,可仿照此方式在model中重現
下面直接上源碼:
2. 源碼
2.1. using_checkbox_item.h
- /**
- * @file using_checkbox_item.h
- * @brief 本文件包含支持復選框item類聲明。
- * @version 1.0.0.0
- * @date 2017.12.18
- * @author Techie亮
- */
- #ifndef _H_USINGCHECKBOXITEM_
- #define _H_USINGCHECKBOXITEM_
- #include <QStandardItem>
- #include <QString>
- /**
- * @brief 支持復選框item類
- * 支持復選框三態轉變-全選對勾、全不選空白、半選黑點
- * 子類會自動通知父子節點item,若不符合設計需要可仿照此方式在model中的setDate重現
- */
- class UsingCheckboxItem : public QStandardItem {
- public:
- /**
- * @brief 構造函數
- * @param item顯示內容
- */
- explicit UsingCheckboxItem(const QString &text);
- /**
- * @brief setData重寫
- * @param value data值
- * @param role data類型
- */
- virtual void setData(const QVariant &value, int role = Qt::UserRole + 1);
- };
- #endif // _H_USINGCHECKBOXITEM_
2.2. using_checkbox_item.cpp
- #include "using_checkbox_item.h"
- //構造函數
- UsingCheckboxItem::UsingCheckboxItem(const QString &text)
- : QStandardItem(text) {
- setCheckable(true);
- }
- //setData重寫
- void UsingCheckboxItem::setData(const QVariant &value, int role) {
- if(role == Qt::CheckStateRole) {//針對復選框變動做操作
- Qt::CheckState check_state = (Qt::CheckState)value.toInt();
- QString mtext=text();
- switch (check_state) {
- case Qt::Unchecked: {//取消
- for(int i = 0, num = rowCount(); i < num; i++) {
- child(i)->setData(Qt::Unchecked, Qt::CheckStateRole);
- }
- //修改內容-必須先修改自己再通知父節點
- QStandardItem::setData(value,role);
- //通知父節點,我取消了選擇,直接告訴父節點半選即可
- if(parent())parent()->setData(Qt::PartiallyChecked, role);
- }
- return;//此事件已完成直接return
- case Qt::PartiallyChecked: {//半選
- Qt::CheckState current_state = checkState();//當前狀態
- int checked_num = 0;//被選擇的數量
- int unchecked_num = 0;//未選擇的數量
- bool is_partially = false;
- Qt::CheckState child_state;
- int m_rowCount = rowCount();
- //遍歷所有子節點
- for(int i = 0; i < m_rowCount; i++) {
- child_state = child(i)->checkState();
- //子節點半選,則直接半選
- switch (child_state) {
- case Qt::PartiallyChecked:is_partially = true;break;
- case Qt::Unchecked:unchecked_num++;break;
- case Qt::Checked:checked_num++;break;
- default:checked_num++;break;
- }
- }
- //根據子節點狀態確定當前節點應該設置的狀態
- Qt::CheckState now_state;
- if(is_partially)
- now_state = Qt::PartiallyChecked;
- else if(checked_num == m_rowCount)
- now_state = Qt::Checked;
- else if(unchecked_num == m_rowCount)
- now_state = Qt::Unchecked;
- else
- now_state = Qt::PartiallyChecked;
- //修改狀態並通知父節點
- if(current_state != now_state) {
- //修改內容-必須先修改自己再通知父節點
- QStandardItem::setData(now_state,role);
- //通知父節點,我的狀態更改,也就是父節點進入半選
- if(parent())parent()->setData(Qt::PartiallyChecked, role);
- }
- }
- return;//此事件已完成直接return
- case Qt::Checked: {//全選
- for(int i = 0, num = rowCount(); i < num; i++) {
- child(i)->setData(Qt::Checked, Qt::CheckStateRole);
- }
- //修改內容-必須先修改自己再通知父節點
- QStandardItem::setData(value,role);
- //通知父節點,我被選了,也就是父節點進入半選
- if(parent()) {
- parent()->setData(Qt::PartiallyChecked, role);
- }
- }
- return;//此事件已完成直接return
- default://如果出現此情況就是錯了,可以加錯誤處理
- break;
- }
- }
- QStandardItem::setData(value,role);
- }
3. 說明
- 重寫了setData方法,但僅對CheckStateRole類型data做了操作,其余類型通過最后的QStandardItem::setData(value,role)直接使用默認方式
- setData中每個case后均直接return,因為會根據value和父子類情況對實際要使用value做修改,最終賦值給QStandardItem::setData不一定是參數value,所以若不返回,必然會調用最后一樣導致出錯
- 系統默認只有兩個狀態切換選中和補選中,所以可以借用這個特性,當一個節點狀態修改時都通知其父類為PartiallyChecked部分選中狀態,由父節點自行判斷子節點情況並設置自身狀態
- 注意一定要先修改自身狀態以后在通知父節點,否則在父節點函數運行過程中自身仍為未修改狀態,會導致判斷錯誤
- 在PartiallyChecked的case中判斷了一下新舊狀態是否改變,若改變會向上一父節點繼續傳遞消息,不改變則立刻停止減少運算量
- 若子節點存在PartiallyChecked狀態的,則當前節點一定為PartiallyChecked
- 注意最頂級item是沒有parent的所以想父節點傳遞消息前一定要判斷parent是否為nullptr
- 選擇一個節點那么此節點一定會在全選-不選兩個狀態切換,而部分選擇僅存在於此節點的子節點發生變動,所以全選-不選兩個case直接對所有子節點賦值
轉載請以鏈接形式標明本文標題和地址:
Techie亮博客 »
QTreeView/QTableView中利用QStandardItem實現復選框三種形態變化