我在寫MarkdownOne的時候, 需要有一個類似各大IDE都有的ProjectExplorer這樣的東西. 我需要的功能比較簡單, 就是顯示外加一些簡單操作而已. 因為自己平日裡愛極了QtCreator這個IDE, 它的ProjectExplorer是相當贊的. 於是一開始我就想反正QtCreator是插件機制的各個模塊之間應該耦合度比較低, 直接看它的源碼下一些功夫應該可以把這部分給摳出來. 但是打開QtCreator1.0的源碼看的時候, 發現比我預想的要復雜, 並不是一時半會兒就能搞定的. 還是自己寫吧, 反正要的功能也不多, 自己實現也還算簡單, 無非數據, 顯示, 操作, 這三樣還有個專業術語MVC.實現效果如下(紅色區域部分):
因為目錄結構其實是一個樹形結構, 那麼在顯示方面, 當屬TreeView了. 而Model呢, 自己遞歸遍歷目錄生成對應的數據, 也簡單, 但除了自己實現之外還有更簡潔的東西, Qt為我們提供了QFileSystemModel. 而在Qt裡面沒有Control的概念而是用Delegate來代替, 反正也差不多. 在這裡ProjectExplorerView, ProjectExplorerModel, ProjectExplorerItemDelegate 分別繼承於QTreeView,QFileSystemModel和QStyledItemDelegate.
在這其中, 其實ProjectExplorerView不是必須的, 因為QTreeView已經可以滿足我們的需求, 這樣做把一些內部實現放到了派生類中, 用戶不必關心這些細節, 以方便以後再其他地方重復利用, 代碼比較簡單, 不廢話了上代碼:
//ProjectExplorerView.h
#ifndef PROJECTEXPLORERVIEW_H
#define PROJECTEXPLORERVIEW_H
#include <QTreeView>
class ProjectExplorerModel;
class ProjectExplorerItemMenu;
class ProjectExplorerMenu;
class ProjectExplorerView : public QTreeView
{
Q_OBJECT
public:
explicit ProjectExplorerView(QWidget *parent = 0);
/**
* @brief setRootPath Sets the directory that is being watched by the model to newPath
* @param path
*/
void setRootPath(const QString &path);
signals:
void signalDoubleClickedFile(const QString &filePath);
void signalDoubleClickedDir(const QString &dirPath);
public slots:
protected:
void mousePressEvent(QMouseEvent *event);
private:
void initSetting();
void initData();
void initGui();
private:
ProjectExplorerModel *pModel_;
ProjectExplorerItemMenu *pItemMenu_;
ProjectExplorerMenu *pMenu_;
};
#endif // PROJECTEXPLORERVIEW_H
//ProjectExplorerView.cpp
#include "ProjectExplorerView.h"
#include <QDebug>
#include <QFileInfo>
#include <QModelIndex>
#include <QMouseEvent>
#include "ProjectExplorerItemDelegate.h"
#include "ProjectExplorerModel.h"
#include "ProjectExplorerItemMenu.h"
#include "ProjectExplorerMenu.h"
ProjectExplorerView::ProjectExplorerView(QWidget *parent)
: QTreeView(parent)
, pModel_(NULL)
, pItemMenu_(NULL)
, pMenu_(NULL)
{
initSetting();
initData();
initGui();
}
void ProjectExplorerView::setRootPath(const QString &path)
{
pModel_->setRootPath(path);
this->setRootIndex(pModel_->index(path));
}
void ProjectExplorerView::mousePressEvent(QMouseEvent *event)
{
if(event->buttons() == Qt::RightButton)
{
QModelIndex index = indexAt(event->pos());
if(!index.isValid())
{
qDebug() << "點了空白處";
pMenu_->move(event->globalPos());
pMenu_->show();
}
else
{
pItemMenu_->move(event->globalPos());
qDebug() << pModel_->fileName(index);
pItemMenu_->show();
}
event->accept();
return;
}
event->ignore();
return QTreeView::mousePressEvent(event);
}
void ProjectExplorerView::initSetting()
{
//this->setAccessibleName("Name");
//按鍵響應編輯
this->setEditTriggers(QAbstractItemView::EditKeyPressed);//只響應鍵盤的編輯事件
//this->setContextMenuPolicy(Qt::CustomContextMenu);
}
void ProjectExplorerView::initData()
{
pModel_ = new ProjectExplorerModel(this);
this->setModel(pModel_);
connect(this, &ProjectExplorerView::doubleClicked, [=](const QModelIndex &index){
QString path = pModel_->filePath(index);
QFileInfo info(path);
if(info.isDir())
{
Q_EMIT signalDoubleClickedDir(path);
}
else if(info.isFile())
{
Q_EMIT signalDoubleClickedFile(path);
}
else if(info.isSymLink())
{
QString source = info.symLinkTarget();
qDebug() << "這個快捷方式是? " << source;
}
else
{
qDebug() << "這是毛? " << info.path();
}
});
pMenu_ = new ProjectExplorerMenu(this);
pItemMenu_ = new ProjectExplorerItemMenu(this);
this->setItemDelegate(new ProjectExplorerItemDelegate());
}
void ProjectExplorerView::initGui()
{
}
或許一些也學Qt的小伙伴看到這一串代碼中connect那一部分有點懵
connect(this, &ProjectExplorerView::doubleClicked, [=](const QModelIndex &index){
QString path = pModel_->filePath(index);
QFileInfo info(path);
if(info.isDir())
{
Q_EMIT signalDoubleClickedDir(path);
}
else if(info.isFile())
{
Q_EMIT signalDoubleClickedFile(path);
}
else if(info.isSymLink())
{
QString source = info.symLinkTarget();
qDebug() << "這個快捷方式是? " << source;
}
else
{
qDebug() << "這是毛? " << info.path();
}
});
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-12/93366p2.htm
Qt 的詳細介紹:請點這裡
Qt 的下載地址:請點這裡