上一节我们成功实现了创建项目的向导界面的开发,这节我们继续去实现电子相册的其他功能。
新建DirTreeWidget类
· 还记得在Qt快速入门到熟练(电子相册项目(一))-CSDN博客里面,我们是在QDockWidget中添加了一个treeWidget作为以后显示目录树的空间。实际上我们完全可以在mainwindow中实现对treeWidget代码的编写,但是我们考虑到之后可能会添加其他的功能,吧代码全部写在主窗口函数中可能会导致一个cpp文件中代码过于臃肿,对于以后的排错也相对来说比骄傲苦难。所以我们决定新建一个DirTreeWidget类作为对代码的实现。然后在ui界面中将之前拖拽生成的treeWidget的父类提升为DirTreeWidget。
重构SlotCreatePro
还记得这个槽函数吗,之前我们在Wizard类里面实现了创建项目的槽函数,但是在这个槽函数中我们当时保留了一个connect函数,就是在向导完成后我们需要将由创建项目向导创建出来的文件夹显示到treeWidget里面,所以我们现在就需要连接到刚刚新建的DirTreeWidget里面的AddDirToTree这个槽函数,但是这时我们就会发现由于我们的treeWidget是在主窗口ui中创建的,当我们new DirTreeWidget的时候,如果槽函数在Wizard类里面,我们的构造函数想要继承父类就比较麻烦,想要将new DirTreeWidget的父类设置到主窗口则需要包含mainwindow.h,但是这样就会造成不同头文件的互引用,可能会产生不必要的错误。一般来说我习惯与在主窗口包含其他组件的头文件,但是其他组件的头文件中不要包含主窗口。
所以经过思考,我最后还是把这个创建项目的槽函数放到了mainwindow里面。实际上创建项目这一过程的产生就是在向导对话框时产生的,逻辑上放在Wizard类中是比较合适的,但是有时候可以做出一些让步,这会让程序变得简单。如果实在是想把槽函数放在Wizard类也不是不行,只不过就需要我在此基础上新建一个设计师类把主窗口的treeWidget给承接过来。
反正对于这个问题还有许多解决办法,我这里只是展示了一种我比较喜欢的方法,大家完全可以采取其他方法去解决这个问题。
void MainWindow::SlotCreatePro(bool){
qDebug() << "slot create pro triggered" << endl;
Wizard wizard(this);
wizard.setWindowTitle(tr("创建项目"));
auto *page = wizard.page(0);
page->setTitle(tr("设置项目配置"));
QVBoxLayout *layout = new QVBoxLayout(page);
layout->setContentsMargins(200, 100, 50, 50);
layout->addWidget(page);
//连接信号和槽
dirtreewidget = new DirTreeWidget(ui->treeWidget);
// ui->verticalLayout->addWidget(dirtreewidget);
connect(&wizard, &Wizard::SigProSettings, dirtreewidget, &DirTreeWidget::AddDirToTree);
wizard.show();
wizard.exec();
delete layout;
//断开所有信号
// disconnect(&wizard);
}
显示创建的文件夹
在设置向导时我们通过wizardPage1中的GetProSettings函数获取到lineEdit中的项目名称和项目路径,然后在wizard点击完成时触发done函数,进而发送信号触发DirTreeWidget的AddDirToTree函数了,从而生成一个项目目录的item。
下面我们就来设计AddDirToTree函数的实现,这里为了检测生成的路径是否重名,我们使用set来进行路径的管理,函数将获取到的路径传进来,然后通过set进行存储,每次存储前进行重名检测,如果set中已经有这个路径,那么程序就会直接退出。如果没有重名,就进行创建创建文件夹完毕以后,需要在treeWidget显示出来,每一个树的结点都是一个Item。所以我们需要再新建一个DirTreeItem,这样方便我们自定义自己新的item节点。
void DirTreeWidget::AddDirToTree(const QString &name, const QString &path)
{
qDebug() << "DirTreeWidget::AddDirToTree name is " << name << " path is " << path << endl;
QDir dir(path);
QString file_path = dir.absoluteFilePath(name);
//检测重名,判断路径和名字都一样则拒绝加入
if(_set_path.find(file_path) != _set_path.end()){
qDebug() << "file has loaded" << endl;
return;
}
//构造项目用的文件夹
QDir pro_dir(file_path);
//如果文件夹不存在则创建
if(!pro_dir.exists()){
bool enable = pro_dir.mkpath(file_path);
if(!enable){
qDebug() << "pro_dir make path failed" << endl;
return;
}
}
_set_path.insert(file_path);
auto * item = new DirTreeItem(this, name, file_path, TreeItem);
item->setData(0,Qt::DisplayRole, name);
item->setData(0,Qt::DecorationRole, QIcon(":/icon/dir.png"));
item->setData(0,Qt::ToolTipRole, file_path);
this->show();
}
创建DirTreeItem类
关于DirTreeItem类,我们写一下他的构造函数,对于Item有可能是相对来说可以叫做根节点,它们是直接使用QTreeWidget 作为父类,然后还需要三个参数,分别是名字,路径和类型。另一个构造函数我们要考虑子目录,往往是有一个QTreeWidgetItem 作为父类,这样的参数不仅需要name,path,type,而且需要知道这个Item的根节点是是谁。
参考上面声明的两个构造函数,我们还需要三个成员变量 :
QString _path;
QString _name;
QTreeWidgetItem* _root;
#ifndef DIRTREEITEM_H
#define DIRTREEITEM_H
#include <QTreeWidgetItem>
class DirTreeItem : public QTreeWidgetItem
{
// Q_OBJECT
public:
DirTreeItem(QTreeWidget *view, const QString & name, const QString & path,int type = Type);
DirTreeItem(QTreeWidgetItem *parent, const QString & name, const QString & path,
QTreeWidgetItem* root, int type = Type);
private:
QString _path;
QString _name;
QTreeWidgetItem* _root;
};
#endif // DIRTREEITEM_H
DirTreeItem::DirTreeItem(QTreeWidget *view, const QString &name, const QString &path, int type):
QTreeWidgetItem (view, type),_path(path),_name(name)
{
}
DirTreeItem::DirTreeItem(QTreeWidgetItem *parent, const QString &name, const QString &path, QTreeWidgetItem *root, int type):
QTreeWidgetItem(parent,type),_path(path),_name(name),_root(root)
{
}
现在我们来build我们的项目,点击新建项目,输入项目名称,点击完成,可以看到在侧边栏出现了我们刚刚创建的项目的文件夹目录。
右键显示菜单
现在我们已经创建了一个新的项目,但是现在这个项目里面并没有内容,我们所要做的是一款电子相册,那么如何向这个项目目录里面添加文件(图片)呢,首先是需要有能够互动的选项。就比如这样:
那么首先我们线要创建这四个Action,然后让它们在我们鼠标点击右键的时候显示出来。
DirTreeWidget::DirTreeWidget(QWidget *parent):QTreeWidget (parent)
{
//隐藏表头
this->header()->hide();
connect(this, &DirTreeWidget::itemPressed, this, &DirTreeWidget::SlotItemPressed);
// connect(this, &DirTreeWidget::itemDoubleClicked, this, &DirTreeWidget::SlotDoubleClickItem);
_action_import = new QAction(QIcon(":/icon/import.png"),tr("导入文件"), this);
_action_setstart = new QAction(QIcon(":/icon/core.png"), tr("设置活动项目"),this);
_action_closepro = new QAction(QIcon(":/icon/close.png"), tr("关闭项目"), this);
_action_slideshow = new QAction(QIcon(":/icon/slideshow.png"), tr("轮播图播放"),this);
}
在DirTreeWidget类的构造函数里,我们设置一个信号与槽,DirTreeWidget类继承自QTreeWidget,在QTreeWidget里面有一个信号函数itemPressed,他的作用是当用户在小部件内按下鼠标按钮时,就会发出这个信号。然后我们编写对应的槽函数。
在槽函数里,我们首先要判断鼠标点击事件的来源,判断是否为右键,如果是右键,那么就会创建一个menu对象,再进行Item类型的判断,因为我们的Item只有是文件夹类型的才会显示出下面的菜单列表,如果是其他类型,菜单显示的内容也会不同。
void DirTreeWidget::SlotItemPressed(QTreeWidgetItem *pressedItem, int column)
{
qDebug() << "ProTreeWidget::SlotItemPressed" << endl;
if(QGuiApplication::mouseButtons() == Qt::RightButton) //判断是否为右键
{
QMenu menu(this);
qDebug() << "menu addr is " << &menu << endl;
int itemtype = (int)(pressedItem->type());
if (itemtype == TreeItem)
{
_right_btn_item = pressedItem;
menu.addAction(_action_import);
menu.addAction(_action_setstart);
menu.addAction(_action_closepro);
menu.addAction(_action_slideshow);
menu.exec(QCursor::pos()); //菜单弹出位置为鼠标点击位置
}
}
}
到这里我们完成了右键显示菜单的相关内容,之后我们将会继续文件夹导入功能的编写,谢谢大家观看,我们一起学习。