其实这里显示目录的难度不大,也就只有几行代码就实现了,较难的在显示三态,这里只实现了checkbox的checked与unchecked的功能。
贴一下代码:
mytreemodel,h
:
#ifndef MYTREEMODEL_H
#define MYTREEMODEL_H
#include
#include
#include
#include
#include
#include
#include
class MyTreeModel : public QDirModel
{
Q_OBJECT
public:
explicit MyTreeModel(QWidget *parent = nullptr);
~MyTreeModel();
QSet<QPersistentModelIndex> checkedIndexes;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
private:
bool recursiveCheck(const QModelIndex &index, const QVariant &value);
signals:
public slots:
};
#endif // MYTREEMODEL_H
mytreeview,h
:
#ifndef MYLISTVIEW_H
#define MYLISTVIEW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
class MyTreeView : public QWidget
{
Q_OBJECT
public:
MyTreeView();
QSet<QPersistentModelIndex> checkedIndexes;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
private:
bool recursiveCheck(const QModelIndex &index, const QVariant &value);
public:
QDirModel *model;
QTreeView *treeView;
public slots:
void mkdir();
void rm();
void slotCustomContextMenu(const QPoint &point);
//void ShowContextMenu(const QPoint& pos);
protected:
// QMenu menu;
};
#endif // MYLISTVIEW_H
main.cpp
:
#include "mytreeview.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyTreeView w;
w.show();
return a.exec();
}
mytreemodel.cpp
:
#include "mytreemodel.h"
MyTreeModel::MyTreeModel(QWidget *parent) : QDirModel(parent)
{
}
MyTreeModel::~MyTreeModel()
{
}
/*flags( )中返回 ItemIsUserCheckable。*/
Qt::ItemFlags MyTreeModel::flags(const QModelIndex &index) const
{
return QDirModel::flags(index) | Qt::ItemIsUserCheckable;
}
/*data( )中判断给定的项是否在checkedIndexes中,有的话就返回Qt::Checked,没有 就返回Qt::Unchecked。*/
QVariant MyTreeModel::data(const QModelIndex &index, int role) const
{
if(role == Qt::CheckStateRole)
{
qDebug()<<"The checkbox is unchecked"<<checkedIndexes.contains(index);
// if(checkedIndexes.contains(index)==Qt::Checked){
// qDebug()<<"The checkbox is checked"<
// return Qt::Checked;
// }
// else if(checkedIndexes.contains(index)==Qt::Unchecked){
// qDebug()<<"The checkbox is unchecked"<
// return Qt::Unchecked;
// }
// else if(checkedIndexes.contains(index)==Qt::PartiallyChecked) {
// qDebug()<<"The checkbox is part checked"<
// return Qt::PartiallyChecked;
// }
return checkedIndexes.contains(index) ? Qt::Checked : Qt::Unchecked;
//这个返回值就只有两种情况,不是真就是假
}
else
{
return QDirModel::data(index, role);
}
}
/*setData( )则把值为Qt::Checked的给定项,以及给定项的所有子孙节点,全都添加到checkedIndexes里。*/
bool MyTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(role == Qt::CheckStateRole)
{
if(value == Qt::Checked)
{
// if(recursiveCheck(index, value)==false){
// }
checkedIndexes.insert(index);//把给点项的子孙节点加入checkedIndexes
if(hasChildren(index) == true)//如果这个节点有子孙节点,递归把所有节点都加入这个index.
{
recursiveCheck(index, value);
}
}
else if(value == Qt::Unchecked)
{
checkedIndexes.remove(index);
if(hasChildren(index) == true)
{
recursiveCheck(index, value);
}
}
else{
qDebug()<<"this is exec";
}
emit dataChanged(index, index);
return true;
}
return QDirModel::setData(index, value, role);
}
/*recursiveCheck( )用于递规添加子节点。*/
bool MyTreeModel::recursiveCheck(const QModelIndex &index, const QVariant &value)
{
if(hasChildren(index))
{
int i;
int childrenCount = rowCount(index);
QModelIndex child;
for(i=0; i<childrenCount; i++)
{
child = QDirModel::index(i, 0, index);
setData(child, value, Qt::CheckStateRole);
}
return QDirModel::setData(child, value, Qt::CheckStateRole);
}
}
mytreeview.cpp
:
#include "mytreeview.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
MyTreeView::MyTreeView()
{
model = new MyTreeModel();
model->setReadOnly(false);//就是说我们可以对其进行修改
model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name);//文件夹优先(QDir::DirsFirst),忽略大小写(QDir::IgnoreCase),而且是根据名字排序(QDir::Name)。
//QDirModel。这个 model 允许我们在 view 中显示操作系统的目录结构。
treeView = new QTreeView;
treeView->setModel(model);//把 model 设置为刚刚的 QDirModel 实例
treeView->header()->setStretchLastSection(true);//当 QTreeView 的宽度大于所有列宽之和时,最后一列的宽度自动扩展以充满最后的边界;否则就让最后一列的宽度保持原始大小。
treeView->header()->setSortIndicator(0, Qt::AscendingOrder);//setSortIndicator()函数是设置哪一列进行排序。
treeView->header()->setSortIndicatorShown(true);//setSortIndicatorShown()函数设置显示列头上面的排序小箭头。setClickable(true)则允许鼠标点击列头。
//treeView->header()->setClickable(true);
treeView->setEditTriggers(QTreeView::NoEditTriggers); //单元格不能编辑
treeView->setSelectionBehavior(QTreeView::SelectRows); //一次选中整行
treeView->setSelectionMode(QTreeView::SingleSelection); //单选,配合上面的整行就是一次选单行
treeView->setAlternatingRowColors(true); //每间隔一行颜色不一样,当有qss时该属性无效
treeView->setFocusPolicy(Qt::NoFocus);
QModelIndex index = model->index(QDir::currentPath());//通过 QDir::currentPath()获取当前 exe 文件运行时路径,并把这个路径当成程序启动时显示的路径。
treeView->expand(index);
treeView->scrollTo(index);//scrollTo()函数是把视图的视口滚动到这个路径的位置;
treeView->resizeColumnToContents(0);//resizeColumnToContents()是要求把列头适应内容的宽度,也就是不产生...符号。
// QHBoxLayout *btnLayout = new QHBoxLayout;
// QPushButton *createBtn = new QPushButton(tr("Create Directory..."));
// QPushButton *delBtn = new QPushButton(tr("Remove"));
// btnLayout->addWidget(createBtn);
// btnLayout->addWidget(delBtn);
QVBoxLayout *mainLayout = new QVBoxLayout(this);//垂直布局
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(treeView, SIGNAL(customContextMenuRequested(const QPoint& )), this, SLOT(slotCustomContextMenu(const QPoint&)));
mainLayout->addWidget(treeView);
// mainLayout->addLayout(btnLayout);
this->setLayout(mainLayout);
//connect(createBtn, SIGNAL(clicked()), this, SLOT(mkdir()));
//connect(delBtn, SIGNAL(clicked()), this, SLOT(rm()));
}
void MyTreeView::slotCustomContextMenu(const QPoint &point) //槽函数定义
{
QMenu *menu = new QMenu(this);
menu->addAction("delete",this,SLOT(rm())); //设置菜单项,并连接槽函数
menu->addAction("add",this,SLOT(mkdir()));
menu->exec(this->mapToGlobal(point));
}
void MyTreeView::mkdir()
{
QModelIndex index = treeView->currentIndex();
if (!index.isValid()) {
return;
}
QString dirName = QInputDialog::getText(this,
tr("Create Directory"),
tr("Directory name"));
if (!dirName.isEmpty()) {
if (!model->mkdir(index, dirName).isValid()) {
QMessageBox::information(this,
tr("Create Directory"),
tr("Failed to create the directory"));
}
}
}
void MyTreeView::rm()
{
QModelIndex index = treeView->currentIndex();
int row = index.row();
if (!index.isValid()) {
return;
}
bool ok;
if (model->fileInfo(index).isDir()) {//判断是一个文件夹吗,无法删除嵌套其他文件夹的文件夹
ok = model->rmdir(index);
} else {
ok = model->remove(index);//判断是一个文件吗
}
if (!ok) {
QMessageBox::information(this,
tr("Remove"),
tr("Failed to remove %1").arg(model->fileName(index)));
}
}
该有的注释我也都基本写在代码里了,这个难度不是特别大,后面会接下去实现三态,以及文件从一个QTreeView复制到另一个QTreeView之中。