QTreeWidget 复选框checkbox使用

使用QTreewidget时,用到复选框。还有一个苛刻的要求,即在选中或取消选中时,还要做一些操作。刚开始参考了网上的一些方法,参考了https://www.cnblogs.com/doubleeleven/articles/3894250.html,使用itemChange(QTreeWidgetItem*,int)信号,可以实现,但是不满足我个人的需求:我在点选时,要在事件中做其他操作,而每个节点的checkbox状态改变时,itemChange都会被触发,如我的例子中,我选中目标1时,目标1的所有子节点会被选中,如果有3个子节点,一共会触发3+1次itemChange,这不是我想看到的。所以,我尝试使用另一种方法,期望满足条件。

本文只是在学习的层面讨论,不讨论方法优劣。时刻抱持实用主义的观点,不管白猫黑猫,只要捉住老鼠就是好猫。

 

头文件:

 1 #ifndef MYDLG_H
 2 #define MYDLG_H
 3 
 4 #include <QDialog>
 5 #include <QTreeWidget>
 6 #include <map>
 7 using namespace std;
 8 
 9 namespace Ui {
10 class MyDlg;
11 }
12 
13 class MyDlg : public QDialog
14 {
15     Q_OBJECT
16 
17 public:
18     explicit MyDlg(QWidget *parent = 0);
19     ~MyDlg();
20 
21 private slots:
22     void on_btnQuit_clicked();
23     void TreeItemClicked(QTreeWidgetItem* item, int col);
24 private:
25     Ui::MyDlg *ui;
26     map<QTreeWidgetItem*, Qt::CheckState> m_mapItemState;
27     
28     
29     void InitTree();//初始化
30     //添加节点
31     QTreeWidgetItem* AddTreeItem(QTreeWidget* pTree, QTreeWidgetItem* parentItem, QString itemTxt);
32     //获取当前的所有checkbox状态,和选中的节点
33     void GetCheckItem(QTreeWidget* pTree, QList<QString>& listTarget);
34     void ChangeChildItemState(QTreeWidgetItem* thisItem);//根据点击的节点,来改变节点的子节点状态
35     void ChangeParentItemState(QTreeWidgetItem* thisItem);//根据点击的节点,来改变节点的父节点状态
36     //获取节点的上次状态
37     Qt::CheckState GetItemState(QTreeWidgetItem* item, map<QTreeWidgetItem*, Qt::CheckState>& mapItemState);
38     
39 };
40 
41 #endif // MYDIALOG_H

 

 

源文件:

  1 #include "MyDlg.h"
  2 #include "ui_MyDlg.h"
  3 #include <QDebug>
  4 
  5 MyDlg::MyDlg(QWidget *parent) :
  6     QDialog(parent),
  7     ui(new Ui::MyDlg)
  8 {
  9     ui->setupUi(this);
 10     InitTree();
 11 
 12     //首次获得节点状态
 13     QList<QString> list;
 14     GetCheckItem(ui->treeWidget, list);
 15 }
 16 
 17 MyDlg::~MyDlg()
 18 {
 19     delete ui;
 20 }
 21 
 22 void MyDlg::on_btnQuit_clicked()
 23 {
 24 
 25 }
 26 
 27 void MyDlg::TreeItemClicked(QTreeWidgetItem *item, int col)
 28 {
 29     if(item->checkState(0) == GetItemState(item, m_mapItemState))//item状态是否改变
 30         return;
 31     ChangeChildItemState(item);
 32     ChangeParentItemState(item);
 33     QList<QString> listTarget;
 34     GetCheckItem(ui->treeWidget, listTarget);
 35     qDebug() << listTarget;
 36 
 37 }
 38 
 39 void MyDlg::InitTree()
 40 {
 41     connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(TreeItemClicked(QTreeWidgetItem*,int)));
 42     ui->treeWidget->header()->setHidden(1);
 43     QTreeWidgetItem* topItem = new QTreeWidgetItem;
 44     topItem->setCheckState(0, Qt::Unchecked);
 45     topItem->setText(0, "目标列表");
 46     ui->treeWidget->addTopLevelItem(topItem);
 47     QTreeWidgetItem* item1 = AddTreeItem(ui->treeWidget, topItem, "目标1");
 48     QList<QString> listTarget;
 49     listTarget << "目标11" << "目标12";
 50     for(int i = 0; i < listTarget.count(); i++){
 51         AddTreeItem(ui->treeWidget, item1, listTarget.at(i));
 52     }
 53 
 54     QTreeWidgetItem* item2 = AddTreeItem(ui->treeWidget, topItem, "目标2");
 55     listTarget.clear();
 56     listTarget << "目标21" << "目标22" << "目标23";
 57     for(int i = 0; i < listTarget.count(); i++){
 58         AddTreeItem(ui->treeWidget, item2, listTarget.at(i));
 59     }
 60 
 61     QTreeWidgetItem* item3 = AddTreeItem(ui->treeWidget, topItem, "目标3");
 62     listTarget.clear();
 63     listTarget << "目标31" << "目标32" << "目标33" << "目标34";
 64     for(int i = 0; i < listTarget.count(); i++){
 65         AddTreeItem(ui->treeWidget, item3, listTarget.at(i));
 66     }
 67 
 68     ui->treeWidget->expandAll();
 69 }
 70 
 71 QTreeWidgetItem *MyDlg::AddTreeItem(QTreeWidget *pTree, QTreeWidgetItem *parentItem, QString itemTxt)
 72 {
 73     QTreeWidgetItem *item = new QTreeWidgetItem(parentItem);
 74     item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
 75     item->setCheckState(0, Qt::Unchecked);
 76     item->setText(0, itemTxt);
 77     return item;
 78 }
 79 
 80 void MyDlg::GetCheckItem(QTreeWidget *pTree, QList<QString> &listTarget)
 81 {//这个本来是为了获取选中的节点文本。后来增加了获取所有节点的状态,以备将来判断节点状态是否改变
 82     m_mapItemState.clear();
 83 
 84     QTreeWidgetItemIterator it(pTree);
 85     while (*it) {
 86         if((*it)->checkState(0) == Qt::Checked){
 87             QString itemTxt = (*it)->text(0);
 88             if(itemTxt.compare("") != 0){
 89                 listTarget.push_back(itemTxt);
 90             }
 91         }
 92         m_mapItemState[(*it)] = (*it)->checkState(0);
 93         ++it;
 94     }
 95 }
 96 //遍历该节点下所有子节点
 97 void MyDlg::ChangeChildItemState(QTreeWidgetItem *thisItem)
 98 {
 99     int nChildCount = thisItem->childCount();
100     if(nChildCount < 1) return;
101 
102     for(int i = 0; i < nChildCount; i++){
103         thisItem->child(i)->setCheckState(0, thisItem->checkState(0));
104         ChangeChildItemState(thisItem->child(i));
105     }
106 }
107 
108 void MyDlg::ChangeParentItemState(QTreeWidgetItem *thisItem)
109 {
110     QTreeWidgetItem* parentItem = thisItem->parent();
111     if(parentItem == NULL) return;
112 
113     int nChildCount = parentItem->childCount();
114     int nSelected = 0;
115     int nPartSelected = 0;
116     for(int i = 0; i < nChildCount; i++){
117         if(parentItem->child(i)->checkState(0) == Qt::Checked){
118             nSelected++;
119         }
120         else if(parentItem->child(i)->checkState(0) == Qt::PartiallyChecked){
121             nPartSelected++;
122         }
123     }
124     //如果该节点有子节点被选中,但选中的节点个数小于子节点数,或者有子节点是半选中状态,则该节点为半选中
125     if((nSelected > 0 && nSelected < nChildCount) || nPartSelected > 0){
126         parentItem->setCheckState(0, Qt::PartiallyChecked);
127     }
128     else if(nSelected == nChildCount){
129         parentItem->setCheckState(0, Qt::Checked);
130     }
131     else {
132         parentItem->setCheckState(0, Qt::Unchecked);
133     }
134     ChangeParentItemState(parentItem);
135 }
136 
137 Qt::CheckState MyDlg::GetItemState(QTreeWidgetItem *item, map<QTreeWidgetItem *, Qt::CheckState> &mapItemState)
138 {
139     map<QTreeWidgetItem*, Qt::CheckState>::iterator iter = m_mapItemState.find(item);
140     if(iter != m_mapItemState.end()){
141         return iter->second;
142     }
143     return Qt::Unchecked;
144 } 

ui文件:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <ui version="4.0">
 3  <class>MyDlg</class>
 4  <widget class="QDialog" name="MyDlg">
 5   <property name="geometry">
 6    <rect>
 7     <x>0</x>
 8     <y>0</y>
 9     <width>400</width>
10     <height>300</height>
11    </rect>
12   </property>
13   <property name="windowTitle">
14    <string>Dialog</string>
15   </property>
16   <layout class="QGridLayout" name="gridLayout">
17    <item row="0" column="0" colspan="2">
18     <widget class="QTreeWidget" name="treeWidget">
19      <column>
20       <property name="text">
21        <string notr="true">1</string>
22       </property>
23      </column>
24     </widget>
25    </item>
26    <item row="1" column="0">
27     <spacer name="horizontalSpacer">
28      <property name="orientation">
29       <enum>Qt::Horizontal</enum>
30      </property>
31      <property name="sizeHint" stdset="0">
32       <size>
33        <width>298</width>
34        <height>20</height>
35       </size>
36      </property>
37     </spacer>
38    </item>
39    <item row="1" column="1">
40     <widget class="QPushButton" name="btnQuit">
41      <property name="text">
42       <string>quit</string>
43      </property>
44     </widget>
45    </item>
46   </layout>
47  </widget>
48  <resources/>
49  <connections/>
50 </ui>

 

posted @ 2020-05-11 09:46  阳光下的小土豆  阅读(8237)  评论(0编辑  收藏  举报