经过一段时间的学习,相信大家对QT的基本用法都有所了解,从这篇文章开始,我准备记录一下电子相册的项目的一个学习过程。
实现项目创建功能
对于这个电子相册的项目,我并没有在一开始就把所有可能用到的功能模块去事无巨细的考虑周全,我采用的方式是写到哪里我们在此基础上在添加功能,这样的好处是可以简化思维逻辑构建的复杂程度,避免在项目初期就由于考虑过多内容逻辑混乱无从下手。
新建mainwindow的项目
不管我们做什么项目,首先需要一个主界面,在主界面的基础上我们进行功能的改进和模块的添加。这里我新建一个mainwindow的项目,不使用之前我们常用的Widget是因为mainwindow的项目自带菜单栏,可以更快构建我们项目的主要功能。
添加菜单栏
新建mainwindow项目完成后,我们就需要在菜单栏中添加我们需要用到的菜单,刚开始我们只需要文件和设置两个选项,在文件列表里面需要添加创建文件和打开文件,设置里面可以暂时不用添加,也可以添加一个背景音乐的选项作为临时凑数。
cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// ui->dockWidget->header()->hide();
//创建菜单栏
QMenu * menu_file = menuBar()->addMenu(tr("文件(&F)"));
//创建项目动作
QAction * act_create_pro = new QAction(QIcon(":/icon/createpro.png"), tr("创建项目"),this);
act_create_pro->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
menu_file->addAction(act_create_pro);
//打开项目动作
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);
//创建设置菜单
QMenu * menu_set = menuBar()->addMenu(tr("设置(&S)"));
//设置背景音乐动作
QAction * act_music = new QAction(QIcon(":/icon/music.png"), tr("背景音乐"),this);
act_music->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
menu_set->addAction(act_music);
}
为主窗口添加QDockWidget
为实现一个电子相册,我们需要一个能够显示文件和图片列表的一个窗口,这里我选择使用一个QDockWidget来作为显示文件列表的窗口,然后在QDockWidget中添加treeWidget和label作为显示列表的容器,然后把QDockWidget设置为NoDockWidgetArea,来限制其可停靠的区域,并且取消其最大化和关闭窗口选项。
添加QSS
观察上方运行结果,可以发现我的界面和你们的可能有些不同,我的界面是经过界面美化过的。在QT中界面美化一般都是通过编写QSS文件,然后在主函数调用的方式来完成界面美化,现在我们就来编写一下暂时所要用到的QSS条目:
创建一个QSS文件将其命名为style.qss
cpp
/*mainwindow 样式*/
MainWindow {
/* 背景色 */
background-color:rgb(46,47,48);
}
/*菜单栏基本样式*/
QMenuBar{
color:rgb(231,231,231);
background-color:rgb(46,47,48);
}
/*菜单基本样式*/
QMenu{
color:rgb(231,231,231);
background-color:rgb(55,55,55);
}
/* 菜单栏选中条目时 */
QMenuBar::item:selected {
background-color:rgb(80,80,80);
}
/*菜单选中条目*/
QMenu::item:selected {
background-color:rgb(39,96,154);
}
QDockWidget:title
{
background-color:rgb(46,47,48);
}
/*为QDockWidget添加边框*/
QDockWidget>QWidget
{
border-color: #9F9F9F;
border-style: solid;
border-width: 1px 1px 1px 1px;
padding-right: 10px;
}
QDockWidget QLabel#label {
color: rgb(231,231,231);
border-color: #9F9F9F;
border-style: dotted;
border-width: 0 0 1px 0;
padding-bottom: 10px;
margin-bottom: 5px;
}
QTreeView {
color:rgb(231,231,231);
background-color:rgb(46,47,48);
border: 0px;
}
QWizard {
color:rgb(231,231,231);
background-color:rgb(46,47,48);
}
QWizard QLabel#tips {
color: red;
}
那么我们创建的qss文件该存放到哪里呢,不错qss文件和其他资源文件一样,都可以存放到我们的资源文件里面。所以我们创建一个QT资源文件,把创建好的qss文件添加进去。有些读者可能注意到了我在添加菜单栏的时候同时为它们设置了QIcon,这里面所用到的图片我一样是添加到了资源文件里面,只不过在之前没有明说,你们也可以选择自己喜欢的QIcon图片。
添加完成后现在我的资源文件的目录如下:
上面我们说过,qss需要在主函数调用才能真正配置成功,所以下面我们就需要在主函数里面把qss里面的格式给它配置到我们的Qt程序中:
cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QFile qss(":/style/style.qss");
if(qss.open(QFile::ReadOnly)){
qDebug("open qss success");
QString style = QLatin1String(qss.readAll());
a.setStyleSheet(style);
qss.close();
}else{
qDebug("Open failed");
}
w.show();
return a.exec();
}
在mainwindow.cpp中添加槽函数
添加两个connect,在菜单文件中有两个QAction,针对这个两个QAction分别编写连接创建项目槽函数和连接打开项目的槽函数。
cpp
//连接创建项目槽函数
wizard = new Wizard(this);
connect(act_create_pro, &QAction::triggered, wizard, &Wizard::SlotCreatePro);
//连接打开项目的槽函数
connect(act_open_pro, &QAction::triggered, this, &MainWindow::SlotOpenPro);
//connect(this, &MainWindow::SigOpenPro, pro_tree_widget, &ProTreeWidget::SlotOpenPro);
创建向导类
点击创建项目,需要弹出一个向导界面,对创建项目进行配置引导。
所以我们点击添加新文件,选择Qt设计师界面类,选择界面模板为QWizard
Wizard类ui自带两个QWizardPage,所以我们完全可以不用单独新建不同的QWizardPage类,但是对于Wizard类没有办法直接调用QWizardPage中registerField函数注册名为 "proPath" 的字段,并将其与 ui->LineEdit 组件相关联。所以对于不需要使用QWizardPage中函数的页面,无需新建QWizardPage类。
我们在向导首页面需要设置项目的name和path,所以我们还要新建一个QWizardPage设计类,将其命名为WizardPage1。设置界面为如图所示
在Wizard类的wizard.ui里面对wizardPage1提升为我们刚才新建的WizardPage1类,这样我们在wizardPage1.ui里面的设计都会继承到Wizard类的wizard.ui里面。
添加创建项目槽函数
之前在mainwindow里面我们连接了一个向导类的槽函数SlotCreatePro,这里我们着手将其实现出来,
cpp
void Wizard::SlotCreatePro(bool){
qDebug() << "slot create pro triggered" << endl;
// Wizard wizard(this);
this->setWindowTitle(tr("创建项目"));
// auto *page = this->page(0);
ui->wizardPage1->setTitle(tr("设置项目配置"));
QVBoxLayout *layout = new QVBoxLayout(ui->wizardPage1);
layout->setContentsMargins(10, 200, 10, 10);
layout->addWidget(ui->wizardPage1);
//连接信号和槽
//connect(&wizard, &Wizard::SigProSettings, dynamic_cast<ProTree*>(_protree),&ProTree::AddProToTree);
this->show();
this->exec();
// disconnect(&wizard);
}
现在我们已经初步实现了向导界面的框架,之后我们只需要编写首页面的处理逻辑,本次的文章就完满完成。
进行WizardPage1逻辑编写
将两个lineEdit注册为wizard的field,保证两个lineEdit是空的时候无法点击下一步,将QLineEdit的textEdited信号和WizardPage1的completeChanged信号连接起来,这样在lineEdit编辑的时候就会发送textEdited信号,进而触发WizardPage1发送completeChanged信号。
setClearButtonEnabled设置为true可以在lineEdit输入数据后显示清除按钮,直接清除已录入的字符。
completeChanged信号是从WizardPage1的基类QWizardPage类继承而来的。completeChanged信号发出后会触发QWizardPage类的isComplete函数。
cpp
WizardPage1::WizardPage1(QWidget *parent) :
QWizardPage(parent),
ui(new Ui::WizardPage1)
{
ui->setupUi(this);
registerField("proPath", ui->lineEdit_2);
registerField("proName", ui->lineEdit);
connect(ui->lineEdit, &QLineEdit::textEdited, this, &WizardPage1::completeChanged);
connect(ui->lineEdit_2, &QLineEdit::textEdited, this, &WizardPage1::completeChanged);
QString curPath = QDir::currentPath();
ui->lineEdit_2->setText(curPath);
ui->lineEdit_2->setCursorPosition( ui->lineEdit_2->text().size());
ui->lineEdit->setClearButtonEnabled(true);
ui->lineEdit_2->setClearButtonEnabled(true);
}
为了实现特定的判断,我们重写isComplete函数。这样我们就能判断文件夹是否合理以及是否已经有项目路径了。
可以根据不满足的条件设置tips提示用户。
cpp
bool WizardPage1::isComplete() const
{
if(ui->lineEdit->text() == "" || ui->lineEdit_2->text() == ""){
return false;
}
//判断是否文件夹是否合理
QDir dir(ui->lineEdit_2->text());
if(!dir.exists())
{
//qDebug()<<"file path is not exists" << endl;
ui->tips->setText("project path is not exists");
return false;
}
//判断路径是否存在
QString absFilePath = dir.absoluteFilePath(ui->lineEdit->text());
// qDebug() << "absFilePath is " << absFilePath;
QDir dist_dir(absFilePath);
if(dist_dir.exists()){
ui->tips->setText("project has exists, change path or name!");
return false;
}
ui->tips->setText("");
return QWizardPage::isComplete();
}
为浏览按钮添加点击后选择文件夹操作,在wizardPage1.ui文件里右键点击浏览按钮,选择转到槽,QT会为我们生成槽函数
cpp
void WizardPage1::on_pushButton_clicked()
{
QFileDialog file_dialog;
file_dialog.setFileMode(QFileDialog::Directory);
file_dialog.setWindowTitle("选择导入的文件夹");
auto path = QDir::currentPath();
file_dialog.setDirectory(path);
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;
ui->lineEdit_2->setText(import_path);
}
在wizardPage1页面点击下一步会跳转到下一页。这一页没什么代码,在ui文件里添加提示即可,然后点击完成按钮完成创建。在完成时我们可以重写QWidzard的done函数。
将页面设置的项目名称和路径传递给ProTree类,ProTree类用来在MainWindow左侧显示树形目录,这个之后介绍。
cpp
void Wizard::done(int result)
{
if(result == QDialog::Rejected){
return QWizard::done(result);
}
QString name, path;
ui->wizardPage1->GetProSettings(name, path);
emit SigProSettings(name, path);
QWizard::done(result);
}
这里面我们定义了一个GetProSettings函数去获取从lineEdit里面得到的name和path信息。然后设计一个信号把name和path信息给发出去。
cpp
void WizardPage1::GetProSettings(QString &name, QString &path)
{
name = ui->lineEdit->text();
path = ui->lineEdit_2->text();
}
到此为止我们创建项目有关的内容已经基本完成,下一节我们将会去实现关于把项目文件列表在treeView里面显示出来。