在QTreeView中维护checkstatus继承
Maintaining checkedstatus inheritance in a QTreeView
我想做一些基本的:你有一个QTreeView
。第一深度只包含文件夹,第二深度只包含文件。我想在每个项目旁边都有一个复选框,显示选中的状态。文件被选中或未选中,文件夹也可以被部分选中,这取决于它们的文件;我相信这一切都是很自然的。
我认为我应该去的方式是使用QStandardItemModel
和QStandardItem
的自定义子类填充它:DescriptionFileItem
。也许这是个坏主意,如果有更简单的方法,请告诉我。
我尝试使用信号和插槽,以便文件上的信号CheckStateChanged
连接到其包含文件夹上的插槽UpdateCheckedStateOnChildStateChanged
。这要求我的DescriptionFileItem
也继承QObject
(顺便说一句,我很惊讶QStandardItem
没有继承QObject
)。我最初希望这将与提供的基类无缝地工作,但它没有:emitDataChanged()
似乎没有触发我的模型的datachchanged()信号…
使用模型的dataChanged
信号直接不起作用:它的调用是受保护的,所以你不能在没有子类化的情况下使用它(我认为这是我的下一步,除非有人能帮助我把它做好)。
此刻我有一个信号->插槽连接,不会工作,我不知道为什么;编译和链接工作正常。下面是代码;也许你能很容易地发现我的错误。我留下了一些注释行,这样你就可以看到我在之前的尝试中做错了什么。谢谢你的建议!
#ifndef DESCRIPTIONFILEITEM_H
#define DESCRIPTIONFILEITEM_H
#include <QStandardItem>
#include <Qt>
class DescriptionFileItem : public QObject, public QStandardItem
{
Q_OBJECT
public:
explicit DescriptionFileItem(const QString & text, bool isFileName=false, QObject* parent = 0);
void setData ( const QVariant & value, int role = Qt::UserRole + 1 );
QVariant data( int role = Qt::UserRole + 1 ) const;
QString text;
Qt::CheckState checkedState;
bool isFileName;
signals:
void CheckStateChanged();
public slots:
void UpdateCheckedStateOnChildStateChanged();
};
#endif // DESCRIPTIONFILEITEM_H
对应的。cpp:
#include "DescriptionFileItem.h"
DescriptionFileItem::DescriptionFileItem(const QString & text, bool isFileName, QObject* parent):
QObject(parent),QStandardItem(text)
{
this->isFileName = isFileName;
checkedState = Qt::Checked;
}
void DescriptionFileItem::setData ( const QVariant & value, int role){
if(role == Qt::CheckStateRole){
Qt::CheckState newCheckState = (Qt::CheckState)value.toInt();
checkedState = newCheckState;
if(isFileName){
if(newCheckState == Qt::Unchecked || newCheckState == Qt::Checked){
for(int i = 0; i<rowCount(); i++){
DescriptionFileItem* child = (DescriptionFileItem*)QStandardItem::child(i);
QModelIndex childIndex = child->index();
child->model()->setData(childIndex,newCheckState, Qt::CheckStateRole);
//child->setCheckState(newCheckState);
//child->setData(newCheckState,Qt::CheckStateRole);
}
/*if(rowCount()>1){
emit this->model()->dataChanged(this->child(0)->index(),this->child(rowCount()-1)->index());
}else{
emit this->model()->dataChanged(this->child(0)->index(),this->child(0)->index());
}*/
}
}else{
emit CheckStateChanged();
}
//emit this->model()->dataChanged(this->index(),this->index());
}else{
QStandardItem::setData(value,role);
}
}
QVariant DescriptionFileItem::data( int role ) const{
if (role == Qt::CheckStateRole){
return checkedState;
}
return QStandardItem::data(role);
}
void DescriptionFileItem::UpdateCheckedStateOnChildStateChanged()
{
Qt::CheckState min = Qt::Checked;
Qt::CheckState max = Qt::Unchecked;
Qt::CheckState childState;
for(int i = 0; i<rowCount(); i++){
DescriptionFileItem* child = (DescriptionFileItem*)QStandardItem::child(i);
childState = (Qt::CheckState) child->data(Qt::CheckStateRole).toInt();
min = min>childState ? childState: min;
max = max<childState ? childState: max;
}
if(min >= max)
setData(min, Qt::CheckStateRole);
else
setData(Qt::PartiallyChecked, Qt::CheckStateRole);
}
和连接/树的构造:
DescriptionFileItem* descFileStdItem = new DescriptionFileItem(descriptionFileName, true);
descFileStdItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled|Qt::ItemIsTristate);
descriptionFileSIModel.appendRow(descFileStdItem);
typedef pair<string,int> indexType;
foreach(indexType index,dataFile->indexes){
DescriptionFileItem* key_xItem = new DescriptionFileItem(index.first.c_str());
descFileStdItem->appendRow(key_xItem);
key_xItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
QObject::connect(key_xItem,SIGNAL(CheckStateChanged()),descFileStdItem,SLOT(UpdateCheckedStateOnModelDataChanged()));
}
编辑:最终答案,感谢stu(见下文)
void DataLoadWidget::ModelItemChanged(QStandardItem *item)
{
QStandardItem* parent = item->parent();
if(parent == 0){
//folder state changed--> update children if not partially selected
Qt::CheckState newState = item->checkState();
if(newState != Qt::PartiallyChecked){
for (int i = 0; i < item->rowCount(); i++)
{
item->child(i)->setCheckState(newState);
}
}
}
else{//child item changed--> count parent's children that are checked
int checkCount = 0;
for (int i = 0; i < parent->rowCount(); i++)
{
if (parent->child(i)->checkState() == Qt::Checked)
checkCount++;
}
if(checkCount == 0)
parent->setCheckState(Qt::Unchecked);
else if (checkCount == parent->rowCount())
parent->setCheckState(Qt::Checked);
else
parent->setCheckState(Qt::PartiallyChecked);
}
}
除非我误解了你的问题,否则你的解决方案似乎过于复杂了。您应该能够使用默认的QStandardItemModel实现轻松地完成此操作。
如何像这样(错误处理省略)?
QObject::connect(model, SIGNAL(itemChanged(QStandardItem*)), someObject, SLOT(modelItemChanged(QStandardItem*)));
然后在信号处理程序中:
void modelItemChanged(QStandardItem* item)
{
QStandardItem* parent = item->parent();
int checkCount = 0;
int rowCount = parent->rowCount();
for (int i = 0; i < rowCount; i++)
{
if (parent->child(i)->checkState() == Qt::Checked)
checkCount++;
}
switch (checkCount)
{
case 0:
parent->setCheckState(Qt::Unchecked);
break;
case rowCount:
parent->setCheckState(Qt::Checked);
break;
default:
parent->setCheckState(Qt::PartiallyChecked);
}
}
这绝不是最优的,但对于您的目的来说可能已经足够了。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 在QTreeView中维护checkstatus继承