使用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
4 #include <QDialog>
5 #include <QTreeWidget>
6 #include <map>
7 using namespace std;
9 namespace Ui {
10 class MyDlg;
11 }
13 class MyDlg : public QDialog
14 {
15 Q_OBJECT
17 public:
18 explicit MyDlg(QWidget *parent = 0);
19 ~MyDlg();
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;
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);
39 };
41 #endif // MYDIALOG_H
1 #include "MyDlg.h"
2 #include "ui_MyDlg.h"
3 #include <QDebug>
5 MyDlg::MyDlg(QWidget *parent) :
6 QDialog(parent),
7 ui(new Ui::MyDlg)
9 ui->setupUi(this);
10 InitTree();
12 //首次获得节点状态
13 QList<QString> list;
14 GetCheckItem(ui->treeWidget, list);
15 }
17 MyDlg::~MyDlg()
18 {
19 delete ui;
20 }
22 void MyDlg::on_btnQuit_clicked()
23 {
25 }
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;
37 }
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 }
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 }
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 }
68 ui->treeWidget->expandAll();
69 }
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 }
80 void MyDlg::GetCheckItem(QTreeWidget *pTree, QList<QString> &listTarget)
81 {//这个本来是为了获取选中的节点文本。后来增加了获取所有节点的状态,以备将来判断节点状态是否改变
82 m_mapItemState.clear();
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;
102 for(int i = 0; i < nChildCount; i++){
103 thisItem->child(i)->setCheckState(0, thisItem->checkState(0));
104 ChangeChildItemState(thisItem->child(i));
105 }
106 }
108 void MyDlg::ChangeParentItemState(QTreeWidgetItem *thisItem)
109 {
110 QTreeWidgetItem* parentItem = thisItem->parent();
111 if(parentItem == NULL) return;
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 }
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>