QT學習教程11-QTreeView顯示系統目錄並實現複選框

完成的功能禿

在這裏插入圖片描述

使用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之中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章