导入项目
之前我们创建一个相册项目是通过向导设置项目名称和路径,再选择指定文件夹内容导入到我们的项目路径,并且copy文件的。这次要做的功能是直接打开一个文件夹,将文件夹内容直接展示在左侧目录树中。
连接打开信号
在mainwindow构造函数里添加打开项目的信号和槽函数
//打开项目动作
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函数
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函数
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,并让他们通信,更新进度框进度以及完成情况。
设计打开逻辑线程类
线程构造函数
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函数
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。
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递归创建子节点。
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如下 布局信息如下 因为布局信息里对widget提升了,比如PicAnimationWid,PicButton,PreListWid等,交给后一篇讲述。