说明
Qt中函数QStandardItem::setAutoTristate()无实际功能,仅作为一个布尔标记。若要实现自动三态复选框功能,需要自行代码构建。
本文通过编写两个派生类,完成了这个功能。类源码和一个示例如下:
源码
//[自动三态item](用于AutoTristateTreeView)
#include "QStandardItem"
class AutoTristateItem : public QStandardItem
{
struct{
int oldCheckState;
bool oldShock;
}info;
void setAutoTristate(bool tristate);
public:
AutoTristateItem() : QStandardItem()
{info.oldCheckState = checkState(); info.oldShock = isAutoTristate();}
AutoTristateItem(const QString &text) : QStandardItem(text)
{info.oldCheckState = checkState(); info.oldShock = isAutoTristate();}
int oldCheckState(){return info.oldCheckState;}
void updateOldCheckState()
{info.oldCheckState = checkState();}//setCheckState()后一般要调用一下该函数, 否则下一次可能不会触发后面的树
//触发当前item之下的所有树的check box与当前item保持一致
void shocking(){info.oldShock = isAutoTristate(); QStandardItem::setAutoTristate(!info.oldShock);}
bool oldShock(){return info.oldShock;}
};
//[自动三态树形视图]
#include "QTreeView"
class AutoTristateTreeView : public QTreeView
{
Q_OBJECT
public:
enum AutoMode{
AutoTristateMode,//必须同时设置setUserTristate(true)
AutoTwoStateMode,//必须同时设置setUserTristate(false)
None
};
explicit AutoTristateTreeView(QWidget *parent = 0) : QTreeView(parent){}
virtual void setModel(QStandardItemModel *model);
AutoMode autoMode(){return info.autoMode;}
void setAutoMode(AutoMode mode){info.autoMode = mode;}
signals:
void tristate_changed_(AutoTristateItem *item);//发送出check box发生变动的item
private slots:
void _item_changed(QStandardItem *item);
private:
struct{
AutoMode autoMode = None;
}info;
};
实现:
void AutoTristateTreeView::setModel(QStandardItemModel *model)
{
QTreeView::setModel(model);
connect(model, &QStandardItemModel::itemChanged, this, &AutoTristateTreeView::_item_changed);
}
void AutoTristateTreeView::_item_changed(QStandardItem *item)
{
// cout << "AutoTristateTreeView::_item_changed - " << endl;
if(((AutoTristateItem *)item)->oldCheckState() != item->checkState() ||//区分是否是checked的改变
((AutoTristateItem *)item)->oldShock() != item->isAutoTristate()){
if(((AutoTristateItem *)item)->oldCheckState() != item->checkState()){
((AutoTristateItem *)item)->updateOldCheckState();
emit tristate_changed_((AutoTristateItem *)item);
cout << "AutoTristateTreeView::_item_changed - Changed item:"
<< qPrintable(item->text()) << endl;
}
for(int i = 0; i < item->rowCount(); ++i) {//只需控制其直接child即可
switch (info.autoMode) {
case AutoTristateMode:
if(item->child(i)->isUserTristate()){
if(item->child(i)->checkState() == item->checkState())
((AutoTristateItem *)(item->child(i)))->shocking();
else item->child(i)->setCheckState(item->checkState());
}
break;
case AutoTwoStateMode:
if(!item->child(i)->isUserTristate()){
if(item->child(i)->checkState() == item->checkState())
((AutoTristateItem *)(item->child(i)))->shocking();
else item->child(i)->setCheckState(item->checkState());
}
break;
default:
break;
}
}
}
}
示例:
AutoTristateTreeView类中带有一个信号函数tristate_changed_(),用于将复选框发生变动的item发送出去。下面示例中使用了这个信号,用于将触发的item输出到窗口,但这里并没有贴出其槽函数的实现。
QStandardItemModel * model = new QStandardItemModel;
AutoTristateItem * item = new AutoTristateItem("test");
item->setCheckable(true);
item->setUserTristate(true);
AutoTristateItem * item2 = new AutoTristateItem("test_2");
item2->setCheckable(true);
item2->setUserTristate(true);
item->appendRow(item2);
AutoTristateItem * item3 = new AutoTristateItem("test_3");
item3->setCheckable(true);
item3->setUserTristate(true);
item->appendRow(item3);
AutoTristateItem * item4 = new AutoTristateItem("test_4");
item4->setCheckable(true);
item4->setUserTristate(true);
item3->appendRow(item4);
model->appendRow(item);
ui->treeView->setModel(model);
ui->treeView->setAutoMode(AutoTristateTreeView::AutoTristateMode);
connect(ui->treeView, &AutoTristateTreeView::tristate_changed_, this, &Widget::_tristate_changed);
调试: