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>