QT 实现电子相册(三)--导入功能和幻灯片ui设计

导入项目

之前我们创建一个相册项目是通过向导设置项目名称和路径,再选择指定文件夹内容导入到我们的项目路径,并且copy文件的。这次要做的功能是直接打开一个文件夹,将文件夹内容直接展示在左侧目录树中。

连接打开信号

在mainwindow构造函数里添加打开项目的信号和槽函数

1
2
3
4
5
6
7
//打开项目动作
QAction * act_open_pro = new QAction(QIcon(":/icon/openpro.png"), tr("打开项目"),this);
act_open_pro->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
menu_file->addAction(act_open_pro);
//连接打开项目的槽函数
connect(act_open_pro, &QAction::triggered, this, &MainWindow::SlotOpenPro);
connect(this, &MainWindow::SigOpenPro, pro_tree_widget, &ProTreeWidget::SlotOpenPro);

当我们点击打开项目时触发SlotOpenPro函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void MainWindow::SlotOpenPro(bool)
{
QFileDialog file_dialog;
file_dialog.setFileMode(QFileDialog::Directory);
file_dialog.setWindowTitle("选择导入的文件夹");

file_dialog.setDirectory(QDir::currentPath());
file_dialog.setViewMode(QFileDialog::Detail);

QStringList fileNames;
if (file_dialog.exec()){
fileNames = file_dialog.selectedFiles();
}

if(fileNames.length() <= 0){
return;
}

QString import_path = fileNames.at(0);
qDebug() << "import_path is " << import_path << endl;
emit SigOpenPro(import_path);
}

该函数打开一个文件对话框,根据选择的文件夹返回我们要打开的路径,然后将这个路径用SigOpenPro信号发送出去。
会触发ProTreeWidget的SlotOpenPro函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void ProTreeWidget::SlotOpenPro(const QString& path)
{
if(_set_path.find(path) != _set_path.end()){
qDebug() << "file has loaded" << endl;
return;
}

_set_path.insert(path);
int file_count = 0;
QDir pro_dir(path);
const QString& proname = pro_dir.dirName();

_thread_open_pro = std::make_shared<OpenTreeThread>(path, file_count, this,nullptr);
_thread_open_pro->start();

_open_progressdlg = new QProgressDialog(this);

//连接更新进度框操作
connect(_thread_open_pro.get(), &OpenTreeThread::SigUpdateProgress,
this, &ProTreeWidget::SlotUpOpenProgress);

connect(_thread_open_pro.get(), &OpenTreeThread::SigFinishProgress, this,
&ProTreeWidget::SlotFinishOpenProgress);

_open_progressdlg->setWindowTitle("Please wait...");
_open_progressdlg->setFixedWidth(PROGRESS_WIDTH);
_open_progressdlg->setRange(0, PROGRESS_MAX);
_open_progressdlg->exec();

}

上述逻辑中,我们创建了一个进度对话框,以及一个线程OpenTreeThread,并让他们通信,更新进度框进度以及完成情况。

设计打开逻辑线程类

线程构造函数

1
2
3
4
5
6
7
OpenTreeThread::OpenTreeThread(const QString &src_path, int &file_count,
QTreeWidget *self, QObject *parent):
QThread (parent),_bstop(false),_src_path(src_path),_file_count(file_count)
,_self(self),_root(nullptr)
{

}

_bstop表示是否终止线程。
_src_path表示打开的文件路径。
_file_count表示文件数量。
_root表示ProTreeItem类型的根节点。
_self表示ProTreeWidget类型的对象。

程序启动后执行run函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void OpenTreeThread::run()
{
OpenProTree(_src_path,_file_count,_self);
if(_bstop&&_root){
auto path = dynamic_cast<ProTreeItem*>(_root)->GetPath();
auto index = _self->indexOfTopLevelItem(_root);
delete _self->takeTopLevelItem(index);
QDir dir(path);
dir.removeRecursively();
return;
}

emit SigFinishProgress(_file_count);
}

run函数内调用OpenProTree导入逻辑生成目录树,然后判断_bstop是否为真并且root有效,说明取消了导入操作,所以删除目录树。
当执行完导入操作后发送完成信号SigFinishProgress。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void OpenTreeThread::OpenProTree(const QString &src_path,
int &file_count, QTreeWidget *self)
{
//创建根节点
QDir src_dir(src_path);
auto name = src_dir.dirName();
auto * item = new ProTreeItem(self, name, src_path, TreeItemPro);
item->setData(0,Qt::DisplayRole, name);
item->setData(0,Qt::DecorationRole, QIcon(":/icon/dir.png"));
item->setData(0,Qt::ToolTipRole, src_path);
_root = item;

//读取根节点下目录和文件
RecursiveProTree(src_path,file_count,self,_root,item, nullptr);
}

OpenProTree创建了根节点,然后调用了递归函数RecursiveProTree递归创建子节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void OpenTreeThread::RecursiveProTree( const QString &src_path, int &file_count, QTreeWidget *self,
QTreeWidgetItem *root, QTreeWidgetItem *parent,QTreeWidgetItem* preitem)
{
QDir src_dir(src_path);
//设置文件过滤器
QStringList nameFilters;
src_dir.setFilter(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot);//除了目录或文件,其他的过滤掉
src_dir.setSorting(QDir::Name);//优先显示名字
QFileInfoList list = src_dir.entryInfoList();
qDebug() << "list.size " << list.size() << endl;
for(int i = 0; i < list.size(); i++){
if(_bstop){
return;
}
QFileInfo fileInfo = list.at(i);
bool bIsDir = fileInfo.isDir();
if (bIsDir)
{
if(_bstop){
return;
}
file_count++;
emit SigUpdateProgress(file_count);
auto * item = new ProTreeItem(_root, fileInfo.fileName(),
fileInfo.absoluteFilePath(), _root,TreeItemDir);
item->setData(0,Qt::DisplayRole, fileInfo.fileName());
item->setData(0,Qt::DecorationRole, QIcon(":/icon/dir.png"));
item->setData(0,Qt::ToolTipRole, fileInfo.absoluteFilePath());

RecursiveProTree(fileInfo.absoluteFilePath(), file_count,
self,root,item, preitem);

}else{
if(_bstop){
return;
}

const QString & suffix = fileInfo.completeSuffix();
if(suffix != "png" && suffix != "jpeg" && suffix != "jpg"){
qDebug() << "suffix is not pic " << suffix << endl;
continue;
}

file_count++;
emit SigUpdateProgress(file_count);

auto * item = new ProTreeItem(parent, fileInfo.fileName(),
fileInfo.absoluteFilePath(), root,TreeItemPic);
item->setData(0,Qt::DisplayRole, fileInfo.fileName());
item->setData(0,Qt::DecorationRole, QIcon(":/icon/pic.png"));
item->setData(0,Qt::ToolTipRole, fileInfo.absoluteFilePath());

if(preitem){
auto* pre_proitem = dynamic_cast<ProTreeItem*>(preitem);
pre_proitem->SetNextItem(item);
}

item->SetPreItem(preitem);
preitem = item;
}
}

emit SigFinishProgress(file_count);
}

这样完成了打开一个文件夹生成项目的功能。

幻灯片SlideShowDlg类的ui设计

我们创建一个名字为SlideShowDlg设计师界面类,然后在ui文件里添加两个QWidget,分别命名为preShow和slideShow。
1 将SlideShowDlg设置为垂直布局,将拉伸比例设置为7比1,这样整体的布局被分为两部分,上部分为slideShow,下部分为preShow,slideShow设置为网格布局,preShow设置为垂直布局。
2 在slideShow里添加两个固定宽度为80像素的widget(slidenextwid和slideprewid),这个两个widget设置为垂直布局,分别在widget里添加button(slidenextBtn和slidepreBtn),
3 在slideShow里添加一个水平布局放在右上角,然后在该布局里添加两个按钮(closeBtn和playBtn)。
4 在slideShow里添加一个widget(命名为picAnimation)设置为网格布局
5 在preShow中添加一个高度固定为120的widget,让其宽度自适应,该widget设置为网格布局,在该widget内部添加一个widget命名为preListWidget,主要用来展示预览图。
幻灯片界面ui如下
https://cdn.llfc.club/1674979781177.jpg
布局信息如下
https://cdn.llfc.club/1674986967186.jpg
因为布局信息里对widget提升了,比如PicAnimationWid,PicButton,PreListWid等,交给后一篇讲述。

源码链接

源码链接
https://gitee.com/secondtonone1/qt-learning-notes