目的:使用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);
}
}