日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Qt樹形控件QTreeView使用2

 gastonfeng 2016-02-14
這種三態(tài)叫Tristate。
要設(shè)置條目有復(fù)選框只需要使用QStandardItem的函數(shù)setCheckable,無論是兩態(tài)還是三態(tài)都需要先setCheckable,setCheckable默認(rèn)是兩態(tài),如果希望是三態(tài)的話,需要再setTristate
示例代碼如下:(樹形視圖節(jié)點(diǎn)的具體添加方法見上篇文章)
  1. QStandardItemModel* model = new QStandardItemModel(ui->treeView);  
  2. model->setHorizontalHeaderLabels(QStringList()<<><>< li=""><><>
  3. QStandardItem* itemProject = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_Project")],QStringLiteral("項(xiàng)目"));  
  4. model->appendRow(itemProject);  
  5. model->setItem(model->indexFromItem(itemProject).row(),1,new QStandardItem(QStringLiteral("項(xiàng)目信息說明")));  
  6. QStandardItem* itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("文件夾1"));  
  7. itemProject->appendRow(itemFolder);  
  8. itemProject->setChild(itemFolder->index().row(),1,new QStandardItem(QStringLiteral("信息說明")));  
  9. itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("文件夾2"));  
  10. itemProject->appendRow(itemFolder);  
  11. for(int i=0;i<5;++i){  
  12.     QStandardItem* itemgroup = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_group")],QStringLiteral("組%1").arg(i+1));  
  13.     itemFolder->appendRow(itemgroup);  
  14.     for(int j=0;j<(i+1);++j){  
  15.         QStandardItem* itemchannel = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_channel")],QStringLiteral("頻道%1").arg(j+1));  
  16.         itemgroup->appendRow(itemchannel);  
  17.         itemgroup->setChild(itemchannel->index().row(),1,new QStandardItem(QStringLiteral("頻道%1信息說明").arg(j+1)));  
  18.     }  
  19. }  
  20. itemProject->setChild(itemFolder->index().row(),1,new QStandardItem(QStringLiteral("文件夾2信息說明")));  
  21. itemProject = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_Project")],QStringLiteral("項(xiàng)目2"));  
  22. model->appendRow(itemProject);  
  23. for(int i =0;i<3;++i)  
  24. {  
  25.     itemFolder = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_folder")],QStringLiteral("項(xiàng)目2文件夾%1").arg(i+1));  
  26.     itemFolder->setCheckable(true);  
  27.     itemFolder->setTristate(true);  
  28.     QStandardItem* itemFolderDes = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_group")],QStringLiteral("文件夾%1組").arg(i+1));  
  29.     itemProject->appendRow(itemFolder);  
  30.     itemProject->setChild(itemFolder->index().row(),1,itemFolderDes);  
  31.     for(int j=0;j<>< li=""><>
  32.     {  
  33.          QStandardItem* item = new QStandardItem(m_publicIconMap[QStringLiteral("treeItem_dataItem")],QStringLiteral("項(xiàng)目%1").arg(j+1));  
  34.          item->setCheckable(true);  
  35.          itemFolder->appendRow(item);  
  36.   
  37.     }  
  38. }  
  39. //關(guān)聯(lián)項(xiàng)目屬性改變的信號(hào)和槽  
  40. connect(model,&QStandardItemModel::itemChanged,this,&Widget::treeItemChanged);  
  41. //connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(treeItemChanged(QStandardItem*)));  
  42. ui->treeView->setModel(model);  


代碼中m_publicIconMap是QMap對(duì)象,用于存放定義好的圖標(biāo),在樹形視圖節(jié)點(diǎn)添加之前進(jìn)行初始化,初始化代碼如下:
  1. m_publicIconMap[QStringLiteral("treeItem_Project")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/Project.png"));  
  2. m_publicIconMap[QStringLiteral("treeItem_folder")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/folder.png"));  
  3. m_publicIconMap[QStringLiteral("treeItem_folder-ansys")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/folder-ansys.png"));  
  4. m_publicIconMap[QStringLiteral("treeItem_group")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/group.png"));  
  5. m_publicIconMap[QStringLiteral("treeItem_channel")] = QIcon(QStringLiteral(":/treeItemIcon/res_treeItemIcon/channel.png"));  

效果圖:

2.三態(tài)復(fù)選框的智能關(guān)聯(lián)

三態(tài)復(fù)選框的主要體現(xiàn)就在樹形控件里,如果子項(xiàng)目全選,父級(jí)需要全選,如果子項(xiàng)目部分選,父級(jí)就是不完全選
下圖是三態(tài)的正確表現(xiàn)方法



但QTreeView在QStandardItem設(shè)置復(fù)選框后,并不是按照規(guī)則的,這時(shí)需要進(jìn)行代碼設(shè)置

2.1 捕獲復(fù)選框改變的信號(hào)

要對(duì)復(fù)選框進(jìn)行操作,首先需要捕獲樹形視圖的復(fù)選框改變發(fā)出的信號(hào)
通過QStandardItemModel設(shè)置的項(xiàng)目,任何改變都會(huì)觸發(fā)void QStandardItemModel::itemChanged(QStandardItem * item)信號(hào)
因此需要定義一個(gè)槽函數(shù)和這個(gè)信號(hào)關(guān)聯(lián)
  1. private slots :  
  2. void treeItem_CheckChildChanged ( QStandardItem * item );  


關(guān)聯(lián)代碼寫在model創(chuàng)建之后的地方:
  1. //關(guān)聯(lián)項(xiàng)目屬性改變的信號(hào)和槽  
  2. connect ( model ,&QStandardItemModel::itemChanged , this ,&Widget::treeItemChanged );  
  3. //connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(treeItemChanged(QStandardItem*)));  

這里使用最新的信號(hào)和槽的關(guān)聯(lián)方法,記得在pro文件中加入如下,使得支持C++11
CONFIG+=c++11
槽函數(shù)的寫法如下:
void Widget :: treeItemChanged ( QStandardItem * item )
{
}

下面開始實(shí)現(xiàn)三態(tài)的自動(dòng)關(guān)聯(lián)(父子節(jié)點(diǎn)checkbox自動(dòng)關(guān)聯(lián))

2.2 父子節(jié)點(diǎn)復(fù)選框自動(dòng)關(guān)聯(lián)實(shí)現(xiàn)

  1. void Widget : : treeItemChanged ( QStandardItem * item )  
  2. {  
  3.     if ( item == nullptr )  
  4.     return ;  
  5.     if ( item - > isCheckable ())  
  6.     {  
  7.         //如果條目是存在復(fù)選框的,那么就進(jìn)行下面的操作  
  8.         Qt : : CheckState state = item - > checkState (); //獲取當(dāng)前的選擇狀態(tài)  
  9.         if ( item - > isTristate ())  
  10.         {  
  11.              //如果條目是三態(tài)的,說明可以對(duì)子目錄進(jìn)行全選和全不選的設(shè)置  
  12.             if ( state != Qt : : PartiallyChecked )  
  13.             {  
  14.                 //當(dāng)前是選中狀態(tài),需要對(duì)其子項(xiàng)目進(jìn)行全選  
  15.                 treeItem_checkAllChild ( item , state == Qt : : Checked ? true : false );  
  16.             }  
  17.         }  
  18.         else  
  19.         {  
  20.             //說明是兩態(tài)的,兩態(tài)會(huì)對(duì)父級(jí)的三態(tài)有影響  
  21.             //判斷兄弟節(jié)點(diǎn)的情況  
  22.             treeItem_CheckChildChanged ( item );  
  23.         }  
  24.     }  
  25. }  


首先要判斷條目的狀態(tài),如果條目是有復(fù)選框的話,那么就進(jìn)行操作。通過函數(shù)isCheckable()可以判斷條目是否有復(fù)選框
在確認(rèn)條目有復(fù)選框后,需要獲取當(dāng)前條目的選中狀態(tài),使用checkState ()函數(shù)可以判斷當(dāng)前條目的選中狀態(tài);
現(xiàn)在分兩種情況:
1.如果條目是三態(tài)的,說明要判斷它的子節(jié)點(diǎn)。條目選中時(shí),所有子節(jié)點(diǎn)都將選中,條目不選中時(shí),所有子節(jié)點(diǎn)都不選中
2.如果條目是兩態(tài)的,說明可能會(huì)影響它的三態(tài)的父節(jié)點(diǎn),當(dāng)兩態(tài)節(jié)點(diǎn)選中且其所有的兄弟節(jié)點(diǎn)都選中,三態(tài)父節(jié)點(diǎn)選中,若兩態(tài)子節(jié)點(diǎn)和其兄弟節(jié)點(diǎn)都沒選中,那么其三態(tài)父節(jié)點(diǎn)將不選中,若果兄弟節(jié)點(diǎn)有選中有不選中,三態(tài)父節(jié)點(diǎn)將是處于不完全選中狀態(tài)

2.2.1 子節(jié)點(diǎn)遞歸全選

treeItem_checkAllChild 函數(shù)是用于使子節(jié)點(diǎn)全選的函數(shù)。這個(gè)函數(shù)實(shí)現(xiàn)如下:

  1. ///  
  2. /// \brief 遞歸設(shè)置所有的子項(xiàng)目為全選或全不選狀態(tài)  
  3. /// \param item 當(dāng)前項(xiàng)目  
  4. /// \param check true時(shí)為全選,false時(shí)全不選  
  5. ///  
  6. void Widget::treeItem_checkAllChild(QStandardItem * item, bool check)  
  7. {  
  8.     if(item == nullptr)  
  9.         return;  
  10.     int rowCount = item->rowCount();  
  11.     for(int i=0;i<>< li=""><>
  12.     {  
  13.         QStandardItem* childItems = item->child(i);  
  14.         treeItem_checkAllChild_recursion(childItems,check);  
  15.     }  
  16.     if(item->isCheckable())  
  17.         item->setCheckState(check ? Qt::Checked : Qt::Unchecked);  
  18. }  
  19. void Widget::treeItem_checkAllChild_recursion(QStandardItem * item,bool check)  
  20. {  
  21.     if(item == nullptr)  
  22.         return;  
  23.     int rowCount = item->rowCount();  
  24.     for(int i=0;i<>< li=""><>
  25.     {  
  26.         QStandardItem* childItems = item->child(i);  
  27.         treeItem_checkAllChild_recursion(childItems,check);  
  28.     }  
  29.     if(item->isCheckable())  
  30.         item->setCheckState(check ? Qt::Checked : Qt::Unchecked);  
  31. }  


通過這個(gè)功能實(shí)現(xiàn),可以看看如何對(duì)樹形節(jié)點(diǎn)的所有子節(jié)點(diǎn)進(jìn)行遍歷,一般樹形節(jié)點(diǎn)的遍歷是通過遞歸來實(shí)現(xiàn)的(遞歸的效率不是最高的,可以把遞歸拆解為循環(huán))。
QStandardItem的child方法可以獲取它的下級(jí)子節(jié)點(diǎn),在這個(gè)方法之前現(xiàn)需要查明有多少個(gè)子節(jié)點(diǎn),rowCount()方法是獲取樹形節(jié)點(diǎn)下一級(jí)的子節(jié)點(diǎn)個(gè)數(shù)(在樹形視圖中,每個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)算作這個(gè)節(jié)點(diǎn)的條目,第一個(gè)節(jié)點(diǎn)就是第一行,第二個(gè)就是第二行,以此類推,如果樹形視圖有多列的話,那么列也會(huì)起作用)。
treeItem_checkAllChild_recursion是個(gè)遞歸函數(shù),通過這個(gè)函數(shù)可以把樹形節(jié)點(diǎn)的所有子節(jié)點(diǎn)遍歷一遍。
通過上面的這個(gè)方法,即可實(shí)現(xiàn)第一種情況。

2.2.2 父節(jié)點(diǎn)遞歸處理


treeItem_CheckChildChanged函數(shù)是用于處理第二種情況的,此函數(shù)主要對(duì)父級(jí)節(jié)點(diǎn)有影響,函數(shù)實(shí)現(xiàn)如下:
  1. ///  
  2. /// \brief 根據(jù)子節(jié)點(diǎn)的改變,更改父節(jié)點(diǎn)的選擇情況  
  3. /// \param item  
  4. ///  
  5. void Widget::treeItem_CheckChildChanged(QStandardItem * item)  
  6. {  
  7.     if(nullptr == item)  
  8.         return;  
  9.     Qt::CheckState siblingState = checkSibling(item);  
  10.     QStandardItem * parentItem = item->parent();  
  11.     if(nullptr == parentItem)  
  12.         return;  
  13.     if(Qt::PartiallyChecked == siblingState)  
  14.     {  
  15.         if(parentItem->isCheckable() && parentItem->isTristate())  
  16.             parentItem->setCheckState(Qt::PartiallyChecked);  
  17.     }  
  18.     else if(Qt::Checked == siblingState)  
  19.     {  
  20.         if(parentItem->isCheckable())  
  21.             parentItem->setCheckState(Qt::Checked);  
  22.     }  
  23.     else  
  24.     {  
  25.         if(parentItem->isCheckable())  
  26.             parentItem->setCheckState(Qt::Unchecked);  
  27.     }  
  28.     treeItem_CheckChildChanged(parentItem);  
  29. }  


此函數(shù)也是一個(gè)遞歸函數(shù),首先要判斷的是父級(jí)是否到達(dá)頂層,到達(dá)底層作為遞歸的結(jié)束,然后通過函數(shù)checkSibling判斷當(dāng)前的兄弟節(jié)點(diǎn)的具體情況,checkSibling方法的實(shí)現(xiàn)如下:

  1. ///  
  2. /// \brief 測(cè)量兄弟節(jié)點(diǎn)的情況,如果都選中返回Qt::Checked,都不選中Qt::Unchecked,不完全選中返回Qt::PartiallyChecked  
  3. /// \param item  
  4. /// \return 如果都選中返回Qt::Checked,都不選中Qt::Unchecked,不完全選中返回Qt::PartiallyChecked  
  5. ///  
  6. Qt::CheckState Widget::checkSibling(QStandardItem * item)  
  7. {  
  8.     //先通過父節(jié)點(diǎn)獲取兄弟節(jié)點(diǎn)  
  9.     QStandardItem * parent = item->parent();  
  10.     if(nullptr == parent)  
  11.         return item->checkState();  
  12.     int brotherCount = parent->rowCount();  
  13.     int checkedCount(0),unCheckedCount(0);  
  14.     Qt::CheckState state;  
  15.     for(int i=0;i<>< li=""><>
  16.     {  
  17.         QStandardItem* siblingItem = parent->child(i);  
  18.         state = siblingItem->checkState();  
  19.         if(Qt::PartiallyChecked == state)  
  20.             return Qt::PartiallyChecked;  
  21.         else if(Qt::Unchecked == state)  
  22.             ++unCheckedCount;  
  23.         else  
  24.             ++checkedCount;  
  25.         if(checkedCount>0 && unCheckedCount>0)  
  26.             return Qt::PartiallyChecked;  
  27.     }  
  28.     if(unCheckedCount>0)  
  29.         return Qt::Unchecked;  
  30.     return Qt::Checked;  
  31. }  

checkSibling用于判斷兄弟節(jié)點(diǎn)的關(guān)系,兄弟節(jié)點(diǎn)之間無外乎三種關(guān)系:
1.全選
2.全不選
3.部分選中
獲取QStandardItem的兄弟節(jié)點(diǎn)有多種方法,這里是通過獲取它的父級(jí)在獲取父級(jí)的子節(jié)點(diǎn)來得到包括它自己的所有兄弟節(jié)點(diǎn),另外QStandardItem可以通過函數(shù)QModelIndex index() const;獲取Item對(duì)應(yīng)的QModelIndex,QModelIndex有QModelIndex QModelIndex::sibling(int row, int column) const方法獲取兄弟節(jié)點(diǎn)。
通過以上幾個(gè)函數(shù),即可實(shí)現(xiàn)QTreeView的復(fù)選框及自動(dòng)識(shí)別勾選的功能。
下面放出效果圖:





    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多