Qt编程:实用小工具集 -- 文件管理器

    基于 Qt C++ 的完整文件管理器实现,支持基本的文件及文件夹的操作如复制、粘贴、删除、重命名等。

项目结构

FileManager/
├── CMakeLists.txt
├── main.cpp
├── include/
│   ├── filemanager.h
│   ├── fileoperations.h
│   ├── filemodel.h
│   └── fileview.h
└── src/
    ├── filemanager.cpp
    ├── fileoperations.cpp
    ├── filemodel.cpp
    └── fileview.cpp

模块说明

  1. FileManager - 主窗口类,负责整体界面布局和模块协调

  2. FileModel - 继承自 QFileSystemModel,提供文件系统数据模型

  3. FileView - 继承自 QTreeView,负责显示文件系统视图和用户交互

  4. FileOperations - 处理所有文件操作逻辑,与模型和视图解耦

1. CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(FileManager)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

find_package(Qt5 REQUIRED COMPONENTS Widgets)

include_directories(include)

file(GLOB SOURCES "src/*.cpp")

add_executable(FileManager main.cpp ${SOURCES})

target_link_libraries(FileManager Qt5::Widgets)

2. main.cpp

#include "include/filemanager.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    FileManager fileManager;
    fileManager.show();
    
    return app.exec();
}

3. filemanager.h

#ifndef FILEMANAGER_H
#define FILEMANAGER_H

#include <QMainWindow>
#include "FileManager/filemodel.h"
#include "FileManager/fileview.h"
#include "FileManager/fileoperations.h"

class FileManager : public QMainWindow
{
	Q_OBJECT

public:
	explicit FileManager(QWidget *parent = nullptr);

	void createMenuBar();
	void createToolBar();

private:
	void setupUi();
	void setupConnections();

	FileModel *model;
	FileView *view;
	FileOperations *operations;
};

#endif // FILEMANAGER_H

 

4. filemanager.cpp

#include "FileManager/filemanager.h"
#include <QToolBar>
#include <QMenu>
#include <QMenuBar>

FileManager::FileManager(QWidget *parent)
	: QMainWindow(parent),
	model(new FileModel(this)),
	view(new FileView(this)),
	operations(new FileOperations(model, this))
{
	setupUi();
	setupConnections();
	view->setModel(model);
	view->setRootIndex(model->index(QDir::homePath()));
}

void FileManager::setupUi()
{
	setWindowTitle("File Manager");
	resize(800, 600);

	setCentralWidget(view);

	// 创建菜单栏
	createMenuBar();

	// 创建工具栏
	createToolBar();
}

void FileManager::createMenuBar()
{
	QMenuBar *menuBar = this->menuBar();

	// 文件菜单
	QMenu *fileMenu = menuBar->addMenu("File(&F)");

	QAction *newFolderAction = fileMenu->addAction("NewFolder(&N)");
	connect(newFolderAction, &QAction::triggered, this, [this]() {
		operations->newFolder(view->currentIndex());
	});

	fileMenu->addSeparator();

	QAction *exitAction = fileMenu->addAction("Exit(&X)");
	connect(exitAction, &QAction::triggered, this, &QMainWindow::close);

	// 编辑菜单
	QMenu *editMenu = menuBar->addMenu("Edit(&E)");

	QAction *copyAction = editMenu->addAction("Copy(&C)");
	connect(copyAction, &QAction::triggered, this, [this]() {
		operations->copyFile(view->currentIndex());
	});

	QAction *cutAction = editMenu->addAction("Cut(&T)");
	connect(cutAction, &QAction::triggered, this, [this]() {
		operations->cutFile(view->currentIndex());
	});

	QAction *pasteAction = editMenu->addAction("Paste(&P)");
	connect(pasteAction, &QAction::triggered, this, [this]() {
		operations->pasteFile(view->currentIndex());
	});

	QAction *deleteAction = editMenu->addAction("Delete(&D)");
	connect(deleteAction, &QAction::triggered, this, [this]() {
		operations->deleteFile(view->currentIndex());
	});

	QAction *renameAction = editMenu->addAction("Renme(&R)");
	connect(renameAction, &QAction::triggered, this, [this]() {
		operations->renameFile(view->currentIndex());
	});

	// 查看菜单
	QMenu *viewMenu = menuBar->addMenu("View(&V)");

	QAction *homeAction = viewMenu->addAction("Home(&H)");
	connect(homeAction, &QAction::triggered, this, [this]() {
		view->setRootIndex(model->index(QDir::homePath()));
	});

	QAction *upAction = viewMenu->addAction("Up(&U)");
	connect(upAction, &QAction::triggered, this, [this]() {
		QModelIndex currentRoot = view->rootIndex();
		if (currentRoot.isValid()) {
			view->setRootIndex(currentRoot.parent());
		}
	});
}

void FileManager::createToolBar()
{
	QToolBar *toolBar = addToolBar("ToolBar");

	// 添加主页按钮
	QAction *homeAction = toolBar->addAction(QIcon::fromTheme("go-home"), "Home");
	connect(homeAction, &QAction::triggered, this, [this]() {
		view->setRootIndex(model->index(QDir::homePath()));
	});

	// 添加上一级按钮
	QAction *upAction = toolBar->addAction(QIcon::fromTheme("go-up"), "Up");
	connect(upAction, &QAction::triggered, this, [this]() {
		QModelIndex currentRoot = view->rootIndex();
		if (currentRoot.isValid()) {
			view->setRootIndex(currentRoot.parent());
		}
	});

	toolBar->addSeparator();

	// 添加常用操作按钮
	QAction *copyAction = toolBar->addAction(QIcon::fromTheme("edit-copy"), "Copy");
	connect(copyAction, &QAction::triggered, this, [this]() {
		operations->copyFile(view->currentIndex());
	});

	QAction *cutAction = toolBar->addAction(QIcon::fromTheme("edit-cut"), "Cut");
	connect(cutAction, &QAction::triggered, this, [this]() {
		operations->cutFile(view->currentIndex());
	});

	QAction *pasteAction = toolBar->addAction(QIcon::fromTheme("edit-paste"), "Paste");
	connect(pasteAction, &QAction::triggered, this, [this]() {
		operations->pasteFile(view->currentIndex());
	});

	QAction *deleteAction = toolBar->addAction(QIcon::fromTheme("edit-delete"), "Del");
	connect(deleteAction, &QAction::triggered, this, [this]() {
		operations->deleteFile(view->currentIndex());
	});
}

void FileManager::setupConnections()
{
	connect(view, &FileView::fileOperationRequested, operations, &FileOperations::handleFileOperation);
}

5. filemodel.h

#ifndef FILEMODEL_H
#define FILEMODEL_H

#include <QFileSystemModel>

class FileModel : public QFileSystemModel
{
	Q_OBJECT

public:
	explicit FileModel(QObject *parent = nullptr);

	QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};

#endif // FILEMODEL_H

6. filemodel.cpp

#include "FileManager/filemodel.h"
#include <QIcon>

FileModel::FileModel(QObject *parent)
	: QFileSystemModel(parent)
{
	setRootPath(QDir::rootPath());
	setReadOnly(false);
}

QVariant FileModel::data(const QModelIndex &index, int role) const
{
	if (role == Qt::DecorationRole && index.column() == 0) {
		QFileInfo info = fileInfo(index);
		if (info.isDir()) {
			return QIcon::fromTheme("folder");
		}
		return QIcon::fromTheme("text-x-generic");
	}
	return QFileSystemModel::data(index, role);
}

 

7. fileview.h

#ifndef FILEVIEW_H
#define FILEVIEW_H

#include <QTreeView>

class FileView : public QTreeView
{
	Q_OBJECT

public:
	explicit FileView(QWidget *parent = nullptr);

public slots:
	void showContextMenu(const QPoint &pos);

signals:
	void fileOperationRequested(const QString &operation, const QModelIndex &index);

protected:
	void contextMenuEvent(QContextMenuEvent *event) override;
	void mouseDoubleClickEvent(QMouseEvent *event) override;

private:
	void setupContextMenu();
};

#endif // FILEVIEW_H

 

8. fileview.cpp

#include "FileManager/fileview.h"
#include <QMenu>
#include <QContextMenuEvent>
#include <QDesktopServices>
#include <QUrl>

FileView::FileView(QWidget *parent)
	: QTreeView(parent)
{
	setContextMenuPolicy(Qt::CustomContextMenu);
	//setupContextMenu();
	//setContextMenuPolicy(Qt::CustomContextMenu);
	connect(this, &QTreeView::customContextMenuRequested,
		this, &FileView::showContextMenu);
}

void FileView::contextMenuEvent(QContextMenuEvent *event)
{
	QModelIndex index = indexAt(event->pos());
	if (!index.isValid()) return;

	QMenu menu(this);

	QAction *openAction = menu.addAction("Open");
	QAction *copyAction = menu.addAction("Copy");
	QAction *cutAction = menu.addAction("Cut");
	QAction *pasteAction = menu.addAction("Paste");
	QAction *deleteAction = menu.addAction("Del");
	QAction *renameAction = menu.addAction("Rename");
	QAction *newFolderAction = menu.addAction("NewFolder");

	QAction *selectedAction = menu.exec(event->globalPos());
	if (!selectedAction) return;

	if (selectedAction == openAction) {
		emit fileOperationRequested("open", index);
	}
	else if (selectedAction == copyAction) {
		emit fileOperationRequested("copy", index);
	}
	else if (selectedAction == cutAction) {
		emit fileOperationRequested("cut", index);
	}
	else if (selectedAction == pasteAction) {
		emit fileOperationRequested("paste", index);
	}
	else if (selectedAction == deleteAction) {
		emit fileOperationRequested("delete", index);
	}
	else if (selectedAction == renameAction) {
		emit fileOperationRequested("rename", index);
	}
	else if (selectedAction == newFolderAction) {
		emit fileOperationRequested("newFolder", index);
	}
}

void FileView::mouseDoubleClickEvent(QMouseEvent *event)
{
	QModelIndex index = indexAt(event->pos());
	if (index.isValid()) {
		emit fileOperationRequested("open", index);
	}
	QTreeView::mouseDoubleClickEvent(event);
}

void FileView::setupContextMenu()
{
	// 上下文菜单已在contextMenuEvent中动态创建
}

void FileView::showContextMenu(const QPoint &pos)
{
	QModelIndex index = indexAt(pos);
	QMenu menu(this);

	// 创建动作并直接连接信号
	QAction *openAction = menu.addAction("open");
	connect(openAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("open", index);
	});

	QAction *copyAction = menu.addAction("copy");
	connect(copyAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("copy", index);
	});

	QAction *cutAction = menu.addAction("cut");
	connect(cutAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("cut", index);
	});

	QAction *pasteAction = menu.addAction("paste");
	connect(pasteAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("paste", index);
	});

	QAction *deleteAction = menu.addAction("delete");
	connect(deleteAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("delete", index);
	});

	QAction *renameAction = menu.addAction("rename");
	connect(renameAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("rename", index);
	});

	QAction *newFolderAction = menu.addAction("newFolder");
	connect(newFolderAction, &QAction::triggered, [this, index]() {
		emit fileOperationRequested("newFolder", index);
	});

	// 显示菜单
	menu.exec(viewport()->mapToGlobal(pos));
}

 

9. fileoperations.h

#ifndef FILEOPERATIONS_H
#define FILEOPERATIONS_H

#include <QObject>
#include <QFileSystemModel>
#include <QStringList>

class FileOperations : public QObject
{
	Q_OBJECT

public:
	explicit FileOperations(QFileSystemModel *model, QObject *parent = nullptr);

public slots:
	void handleFileOperation(const QString &operation, const QModelIndex &index);
	void newFolder(const QModelIndex &index);
	void copyFile(const QModelIndex &index);
	void cutFile(const QModelIndex &index);
	void pasteFile(const QModelIndex &index);
	void deleteFile(const QModelIndex &index);
	void renameFile(const QModelIndex &index);
private:
	void openFile(const QModelIndex &index);
	bool copyDirectory(const QString &srcPath, const QString &dstPath);

	QFileSystemModel *model;
	QStringList copiedFiles;
	enum ActionType { Copy, Cut } currentAction;
};

#endif // FILEOPERATIONS_H

 

10. fileoperations.cpp

#include "FileManager/fileoperations.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QDir>
#include <QFileInfo>
#include <QDesktopServices>
#include <QUrl>

FileOperations::FileOperations(QFileSystemModel *model, QObject *parent)
	: QObject(parent), model(model)
{
}

void FileOperations::handleFileOperation(const QString &operation, const QModelIndex &index)
{
	if (operation == "open") {
		openFile(index);
	}
	else if (operation == "copy") {
		copyFile(index);
	}
	else if (operation == "cut") {
		cutFile(index);
	}
	else if (operation == "paste") {
		pasteFile(index);
	}
	else if (operation == "delete") {
		deleteFile(index);
	}
	else if (operation == "rename") {
		renameFile(index);
	}
	else if (operation == "newFolder") {
		newFolder(index);
	}
}

void FileOperations::openFile(const QModelIndex &index)
{
	QString filePath = model->filePath(index);
	if (model->isDir(index)) {
		emit model->layoutAboutToBeChanged();
		emit model->layoutChanged();
	}
	else {
		QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
	}
}

void FileOperations::copyFile(const QModelIndex &index)
{
	copiedFiles.clear();
	currentAction = Copy;
	copiedFiles.append(model->filePath(index));
}

void FileOperations::cutFile(const QModelIndex &index)
{
	copiedFiles.clear();
	currentAction = Cut;
	copiedFiles.append(model->filePath(index));
}

void FileOperations::pasteFile(const QModelIndex &index)
{
	if (copiedFiles.isEmpty()) return;

	QString destinationPath;
	if (index.isValid() && model->isDir(index)) {
		destinationPath = model->filePath(index);
	}
	else {
		destinationPath = model->filePath(model->parent(index));
	}

	foreach(const QString &filePath, copiedFiles) {
		QFileInfo fileInfo(filePath);
		QString newPath = destinationPath + QDir::separator() + fileInfo.fileName();

		if (currentAction == Copy) {
			if (fileInfo.isDir()) {
				copyDirectory(filePath, newPath);
			}
			else {
				QFile::copy(filePath, newPath);
			}
		}
		else if (currentAction == Cut) {
			QFile::rename(filePath, newPath);
		}
	}

	if (currentAction == Cut) {
		copiedFiles.clear();
	}
}

void FileOperations::deleteFile(const QModelIndex &index)
{
	QString filePath = model->filePath(index);

	QMessageBox::StandardButton reply;
	reply = QMessageBox::question(nullptr, "Confirm Del", "Are u sure delete " + filePath + " ?",
		QMessageBox::Yes | QMessageBox::No);

	if (reply == QMessageBox::Yes) {
		if (model->isDir(index)) {
			QDir dir(filePath);
			dir.removeRecursively();
		}
		else {
			QFile::remove(filePath);
		}
	}
}

void FileOperations::renameFile(const QModelIndex &index)
{
	QString oldName = model->fileName(index);
	bool ok;
	QString newName = QInputDialog::getText(nullptr, "Rename", "New Name:", QLineEdit::Normal, oldName, &ok);

	if (ok && !newName.isEmpty()) {
		QString oldPath = model->filePath(index);
		QString newPath = model->filePath(index.parent()) + QDir::separator() + newName;

		if (!QFile::rename(oldPath, newPath)) {
			QMessageBox::warning(nullptr, "Error", "Rename failed...");
		}
	}
}

void FileOperations::newFolder(const QModelIndex &index)
{
	QString parentPath;
	if (index.isValid() && model->isDir(index)) {
		parentPath = model->filePath(index);
	}
	else {
		parentPath = model->filePath(model->parent(index));
	}

	bool ok;
	QString folderName = QInputDialog::getText(nullptr, "New Folder", "Folder Name:", QLineEdit::Normal, "", &ok);

	if (ok && !folderName.isEmpty()) {
		QString newPath = parentPath + QDir::separator() + folderName;
		QDir dir;
		if (!dir.mkdir(newPath)) {
			QMessageBox::warning(nullptr, "Error", "New folder failed..");
		}
	}
}

bool FileOperations::copyDirectory(const QString &srcPath, const QString &dstPath)
{
	QDir dir(srcPath);
	if (!dir.exists()) return false;

	foreach(const QString &d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
		QString dst = dstPath + QDir::separator() + d;
		dir.mkpath(dst);
		copyDirectory(srcPath + QDir::separator() + d, dst);
	}

	foreach(const QString &f, dir.entryList(QDir::Files)) {
		QFile::copy(srcPath + QDir::separator() + f, dstPath + QDir::separator() + f);
	}

	return true;
}

 

功能说明

这个文件管理器实现了以下功能:

  1. 基本文件浏览:使用 QFileSystemModel 和 QTreeView 显示文件系统结构

  2. 文件操作

    • 打开文件/目录

    • 复制文件/目录

    • 剪切文件/目录

    • 粘贴文件/目录

    • 删除文件/目录

    • 重命名文件/目录

    • 新建文件夹

  3. 导航功能

    • 主页按钮:返回用户主目录

    • 向上按钮:返回上一级目录

  4. 用户界面

    • 右键上下文菜单

    • 工具栏快捷操作

    • 确认对话框

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值