前言
为了实现如标题的功能,我真的是差点放弃了,还好我没放弃,当然,我也没办法放弃……
效果图
先看一下最终的效果图,左侧显示了整个D盘的文件系统结构(只包含文件夹),右侧显示左侧点击项的文件结构详情(包括文件夹及文件)。可以看到当我勾选右侧的文件夹,无论左侧对应项,还是右侧的子级文件都进行了相应的联动。
思路及代码
像Windows系统的文件资源管理器,因为涉及的文件结构的复杂和数量之大,像以前操作普通的、简单数据那样,将所有数据加载根本不合适。而这次我写的项目就正好碰到了,只能想办法解决。而要实现此功能难点有:
1>数据量大,树形关系过于庞大;
2>点击勾选联动,并且保持左右一致,并且界面数据统一变化;
3>点击过快可能导致冲突,崩溃(此问题跟我的实现方法有很大的关系)。
最终的解决办法:
1>选中项展开时,只显示两层文件:子级项,及孙级项。因为展开选中项时,首先显示的是子级,为了显示子级下是否还有文件夹,能否展开,所以展开两层。
2>为了保持数据的一致,我将存储数据的结构体设置为成员变量,而每一项的数据(data)存储着指向成员变量中与本项相关的结构体;本侧的联动,通过迭代实现;而左右的一致,则是 根据数据的一致性,重新刷新项的勾选状态和项的数据存储。(大概思路这样,详细逻辑更为复杂)
3>由于我每项的数据存储着指向成员变量中与本项相关的结构体,即指向本项数据及其家族数据的结构体,而点击过快时,虽然代码执行完了,但是内部资源可能还在占用,所以可能会出现占用资源的冲突,属于“牵一发动全身”(可能跟电脑的多核有关)。所以就崩了,为了防止操作过快,所以我每次点击后加了一个一秒的动画。
左侧展开
左侧展开比较简单,就是需要判断一下是否需要添加显示项,即判断展开项的孙级是否有添加到界面上,有则返回,没有则添加。
void FileSystemWidget::addChildrenFolderAfterLeftExpend(QTreeWidgetItem *pCurItem)
{
disconnect(ui->treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(addChildrenFolderAfterLeftExpend(QTreeWidgetItem*)));
myWaitDlg.showGif();
//判断是否需要添加显示项
bool flag=true;
for(int i=0;i<pCurItem->childCount();i++)
{
QTreeWidgetItem* childItem=pCurItem->child(i);
QVariant var = childItem->data(0, Qt::UserRole + 1);
if(var.canConvert<MyFileData*>())
{
MyFileData* rootDir=var.value<MyFileData*>();
if (rootDir->fileordir==SYS_DIRECTORY)
{//判断是否是文件夹
int childCount=childItem->childCount();
if(childCount!=0)
{
flag=true;
break;
}else{
flag=false;
break;
}
}
}
}
//添加显示项
if(!flag)
{
for(int i=0;i<pCurItem->childCount();i++)
{
QTreeWidgetItem* childItem=pCurItem->child(i);
bool ischecked;
QVariant var = childItem->data(0, Qt::UserRole + 1);
if (var.canConvert<MyFileData*>())
{
MyFileData* page = var.value<MyFileData*>();
ischecked = page->isChecked;
childItem->setData(0, Qt::UserRole + 1, QVariant::fromValue(page));
}