完成的功能禿
使用QTreeView顯示系統目錄
其實這裏顯示目錄的難度不大,也就只有幾行代碼就實現了,較難的在顯示三態,這裏只實現了checkbox的checked與unchecked的功能。
貼一下代碼:
mytreemodel,h
:
#ifndef MYTREEMODEL_H
#define MYTREEMODEL_H
#include <QWidget>
#include <QDirModel>
#include <QWidget>
#include <QtWidgets>
#include <QtCore>
#include <QtGui>
#include <QSet>
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 <QtGui>
#include <QWidget>
#include <QDirModel>
#include <QTreeView>
#include <QMenu>
#include <QtCore>
#include <QtGui>
#include <QSet>
#include <QPersistentModelIndex>
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 <QApplication>
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"<<checkedIndexes.contains(index);
// return Qt::Checked;
// }
// else if(checkedIndexes.contains(index)==Qt::Unchecked){
// qDebug()<<"The checkbox is unchecked"<<Qt::PartiallyChecked;
// return Qt::Unchecked;
// }
// else if(checkedIndexes.contains(index)==Qt::PartiallyChecked) {
// qDebug()<<"The checkbox is part checked"<<checkedIndexes.contains(index);
// 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 <QHBoxLayout>
#include <QPushButton>
#include <QTreeView>
#include <QHeaderView>
#include <QTableWidget>
#include <QInputDialog>
#include <QMessageBox>
#include <QMenu>
#include <QAbstractItemView>
#include <QDebug>
#include <mytreemodel.h>
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之中。