目的:使用QTreeWidget来浏览硬盘目录的文件结构。
功能要求:
1.选择某一磁盘根目录后,显示根目录下的文件和文件夹,且显示对应的图标;
2.单击列表项的箭头区域展开和折叠,展开时加载下一层级的文件和文件夹;
3.单击列表项的图标或者文本区域为选中状态;
4.样式设置,包括边框,表头视图、底色、选中、鼠标Hover,滚动条的样式。
实现方案:
2.单击列表项的箭头区域展开和折叠,展开时加载下一层级的文件和文件夹;
默认情况下单击QTreeWidgetItem可展开折叠,即连接一下信号槽即可:
connect(ui.m_treeWidget, &QTreeWidget::itemClicked, this, &CDemoSettingsView::slotClicked);
但是本文单击需要选中Item,不展开,所以设计为子类化QTreeWidgetItem,通过事件过滤来重发itemClick信号。参考代码实现如下:
bool CDirsTreeWidget::eventFilter(QObject * watched, QEvent * event)
{if (watched == viewport()){if (event->type() == QEvent::MouseButtonPress) {QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);if (mouseEvent->button() == Qt::LeftButton) {QTreeWidgetItem *item = this->itemAt(mouseEvent->pos());int count = this->indexOfTopLevelItem(item);QRect rc = this->visualItemRect(item);if (item != nullptr) {QPoint pos = mouseEvent->pos();if (pos.x() < rc.x()) {m_arrowPress = true;}}}}else if (event->type() == QEvent::MouseButtonRelease){QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);if (mouseEvent->button() == Qt::LeftButton) {QTreeWidgetItem *item = this->itemAt(mouseEvent->pos());if (item != nullptr) {QPoint pos = mouseEvent->pos();QRect rc = this->visualItemRect(item);if (pos.x() < rc.x()) {if (m_arrowPress){emit itemClicked(item, 0);m_arrowPress = false;return true;}}}}}}return QTreeWidget::eventFilter(watched, event); // 事件未被接受,传递给父类处理
}
其中 QRect rc = this->visualItemRect(item);可获得箭头X的右侧范围,通过判断这个值就可以限定到点击点头才发送itemClick信号,从而实现展开/折叠、选中分开。然后再itemClick的槽函数中进一步获取文件和文件夹。参考代码如下:
void CDemoSettingsView::slotClicked(QTreeWidgetItem * item, int column)
{if (item->data(0, Qt::UserRole + 1).toBool()) // 为true,已经添加过了,不用再添加了return;item->setData(0, Qt::UserRole + 1, true);QString file = item->data(0, Qt::UserRole).toString() + item->text(0);QFileInfo* fileInfo = new QFileInfo(file);if (fileInfo->isDir()) {getFileOnDirectory(item, file); // 是文件夹就获取里面的文件,添加子节点}item->setExpanded(true);
}void CDemoSettingsView::getFileOnDirectory(QTreeWidgetItem* item, QString directoryPath)
{QDir dir(directoryPath);QFileInfoList fileInfoList = dir.entryInfoList();QFileIconProvider iconProvider;for (QFileInfo fileInfo : fileInfoList) {if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")continue;QString filepath = fileInfo.path();QString filename = fileInfo.fileName();QTreeWidgetItem* child = new QTreeWidgetItem();child->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless);child->setText(0, filename);child->setIcon(0, QIcon(iconProvider.icon(fileInfo)));child->setData(0, Qt::UserRole, filepath+"/"); child->setData(0, Qt::UserRole + 1, false); item->addChild(child); }
}