QT项目----电子相册(1)


前言

提示:这里可以添加本文要记录的大概内容:
我们今天开始制作QT的第一个项目–电子相册,用到的都是之前发布的基础知识,我会在Github上同步我的进程,所有代码开源 CSDN中仅放部分代码!!!!!
本项目所使用的知识点
QListWidgetQTreeWidget双缓冲绘图信号槽动画效果绘图事件鼠标事件,qss等知识

最终可以实现一个可以有背景音乐,自动播放照片的电子相册
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一. 主页面框架

首先我们先把主页面框架做出来,首页的左侧是一个目录树,存放相册,右侧是显示照片的取余
这里我们直接用mainwindow.ui实现即可

在这里插入图片描述

1.创建菜单栏

我们在顶部先创建菜单栏

(1)代码部分

//创建菜单
    QMenu * menu_file=menuBar()->addMenu(tr("文件(&F)"));
    //创建设置菜单
    QMenu * menu_set=menuBar()->addMenu(tr("设置(&S)"));

    //新建
    QAction *act_creat_pro=new QAction
    (QIcon(":/photo/7a96a759b1e628c15d2992e8da2bebf.jpg"),tr("创建相册"),this);
    //快捷键
    act_creat_pro->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
    menu_file->addAction(act_creat_pro);

    //打开
    QAction * act_open_pro=new QAction
    (QIcon(":/photo/e38198c26dc52b95a224af050b0951e.jpg"),tr("打开相册"),this);
    //快捷键
    act_open_pro->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
    menu_file->addAction(act_open_pro);


    //设置背景音乐
    QAction* act_music=new QAction
    (QIcon(":/music/bandicam 2025-04-13 14-51-23-941.mp3"),tr("播放背景音乐"),this);
    act_music->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
    menu_set->addAction(act_music);

(2)代码解析

menuBar是QT自带的,表示顶部状态栏

我们这创建了两个菜单,一个menu_file文件 一个menu_set设置
然后在两个菜单中分别加入两个动作,比如我现在有个文件菜单,我鼠标点击文件的时候,下方会显示创建相册和打开相册两个选项
并且还给每个按键加入了一个快捷键

(3)实现效果

在这里插入图片描述
在这里插入图片描述
我们发现此时都是白的,显然不好看,我们此处使用qss进行美化一下

2.qss样式美化菜单栏

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: rgb(55,55,55); /* 背景颜色 */
}

/* 选中菜单项时的样式 */
QMenuBar::item:selected {
    background-color: rgb(80,80,80); /* 选中时背景 */
}

/* 选中菜单项时的样式 */
QMenu::item:selected {
    background-color: rgb(39,96,154 ); /* 选中时背景 */
}

/*创建*/
QWizard{
    color:rgb(231,231,231);
    background-color:rgb(46,47,48);
}

(1)代码解析

1.设置装窗口样式

MainWindow {
    background-color: rgb(46,47,48); /* 设置主窗口背景颜色 */
}

将主窗口(mainwindow)的背景设置为深灰色
这里用了rgb 网上直接搜rgb颜色标记就行

2.设置菜单栏样式

QMenuBar {
    color: rgb(231,231,231); /* 文字颜色 */
    background-color: rgb(46,47,48); /* 背景颜色 */
}

设置菜单栏的背景颜色为深灰色,字体颜色为浅灰色

3.设置菜单项样式

QMenu {
    color: rgb(231,231,231); /* 文字颜色 */
    background: rgb(55,55,55); /* 背景颜色 */
}

将字体颜色设置为白色,背景为浅灰色

4.菜单栏中选中项样式

QMenuBar::item:selected {
    background-color: rgb(80,80,80); /* 选中时背景 */
}

当鼠标悬停或选中菜单栏的某个菜单项时,该项背景变为中灰色

5.菜单中的选中项样式

QMenu::item:selected {
    background-color: rgb(39,96,154); /* 选中时背景 */
}

当鼠标悬停或点击菜单内的选项时,该选项背景变为蓝色调,更醒目

3.qss样式美化后效果

在这里插入图片描述
在这里插入图片描述

4.如何将qss样式添加?

我们在main.cpp的开始显示窗口前 我们加入我们写好的qss样式表即可

QFile qss(":/style/style.qss");
if(qss.open(QFile::ReadOnly))//以只读的方式打开
{
	QString style=QLatin1String(qss.readAll());
	a.setStyleSheet(style);//设置样式表
}
else{//打开失败
	return 0;
}

(1)代码解析

QString style = QLatin1String(qss.readAll());

🌟 作用分解讲解

  1. qss.readAll()
    这部分表示:

    从打开的 qss 文件中读取全部内容(即整个 QSS 样式表)。

    返回类型是 QByteArray,即字节数组(不是 QString 字符串!)。

  2. QLatin1String(…)
    这是一个 Qt 提供的辅助类,用来将 Latin1 编码的字节数组(就是标准英文+常见西文字符编码)转换为一个 QString。

    它和 QString::fromUtf8(…) 类似,但只用于 Latin1 编码(不是中文或特殊符号)。

  3. 为什么不直接用 QString?
    因为 readAll() 返回的是 QByteArray,如果你直接赋值给 QString,可能会使用默认的编码方式,可能不是你想要的结果。
    使用 QLatin1String(…) 明确地告诉 Qt:“我读取的这个字节内容是 Latin1 编码的”,这样转换成 QString 更安全。

✅ 所以这一句完整理解是:
“从样式文件中读取所有内容(QByteArray),用 Latin1 编码方式转换为 QString 类 型,赋值给变量 style

二. 加入注册页面的向导Wizard

向导类Wizard框架思路图

在这里插入图片描述

我们进入软件 一开始是没有相册的,用户可以选中创建相册,然后选择相册名字和存放的相册路径
这里我们用到Qt中的设计师界面类 Wizard
在这里插入图片描述
然后此时有两个页面,我们再添加两个子类进来,重写这两个页面即可
第一个页面ProSetPage注册页面,第二个ConfirmPage完成页面
我们这里重写了Wizard中的两个子页面,那么Wizard.ui中的两个页面的类我们需要提升为我们加入的这两个类对象
在这里插入图片描述

(1)完成ProSetPage的ui部分

在这里插入图片描述
这里我们顶部输入名字和存放路径,路径的右侧有个浏览按钮,点击可以打开目录选择存放地址,然后下面有个tips 是一个label 如果用户输入错误的路径 我们会进行提示
两个弹簧的作用是为了让界面更美观

(2)如何进入注册界面向导类

当我们点击左上角文件的创建相册的时候,会进入这个注册页面,所以我们对创建相册这个按钮进行信号与槽的连通

//连接信号与槽  创建项目
    connect(act_creat_pro,&QAction::triggered,this,&MainWindow::SlotCreatePro);

然后我们直接在mainwindow.cpp主窗口中实现这个函数即可

void MainWindow::SlotCreatePro(bool)
{
    //qDebug()<<"slot create pro triggered"<<endl;
    Wizard wizard(this);//构造函数 父窗口设置为mainwindow
    wizard.setWindowTitle(tr("创建相册"));
    auto *page=wizard.page(0);//第一页
    page->setTitle(tr("相册名称与存放路径"));
    //连接信号与槽 把项目配置传回来todo
    //connect(&wizard,&Wizard::SigProSettings,
   // dynamic_cast<ProTree*>    (_protree),&ProTree::AddProTree);
    wizard.resize(600,400);
    //展示
    wizard.show();
    wizard.exec();
    //断开所有信号todo
    disconnect();

}

中间注销掉的内容是后续我们确定完名字和路径点击完成的时候,要把这个回传回来,我们要放入左侧的目录树中,现在我们先不考虑这部分

此时我们完成到这一步,点击创建相册就会跳出这个窗口

在这里插入图片描述
这里我已经写好了qss样式和目录树,大家做到这与我不一样没关系

(3)实现ProSetPage.cpp

我们打开这个注册页面以后,肯定是准备让用户输入名字和路径了,我们为了防止用户在没有输入名字和路径的情况下就点击下一步,这里我们用注册域来限制用户必须输入名字与正确路径

registerField("proName*",ui->lineEdit);//这里*代表必填
registerField("proPath",ui->lineEdit_2);

此时用户在不断的输入名字和路径
我们要怎么判断用户是否输入的是正确的名字和路径呢
这里我们用到QWizard中的isComplete函数
在这里插入图片描述
我们重写这个虚函数即可

1.介绍isComplete

在这里插入图片描述
我们通过信号与槽 当用户输入这个名字与路径的时候,自动触发这个函数即可

connect(ui->lineEdit,&QLineEdit::textEdited,this,
&ProSetPage::completeChanged);//触发iscomplete函数
    connect(ui->lineEdit_2,&QLineEdit::textEdited,this,
    &ProSetPage::completeChanged);

这里的信号是completeChanged
🔔 当你发出 completeChanged() 信号时,Qt 会自动重新调用一次 isComplete() 函数,用于判断当前页是否“完成”

问题一:为什么此处用的是**&ProSetPage::completeChanged** 而不是
&QWizard::completeChanged
我们的ProSetPage是继承与QWizard 所以也能调用他的虚函数,但为什么这里不能用QWizard,因为它不是我当前对象(this)的直接成员函数

2.重写iscomplete函数

为了实现一些特定的判断 我们需要重新实现这个函数,因为并不是用户输入了名字和路径就能点击下一步,要输入正确的路径才行

//实现强制用户输入正确路径
bool ProSetPage::isComplete() const
{
    if(ui->lineEdit->text()==""||ui->lineEdit_2->text()==""){
        return false;//必须要输入
    }

    QDir dir(ui->lineEdit_2->text());//将文本当成路径 判断此路径是否存在
    if(!dir.exists()){
        ui->tips->setText("路径不存在!");
        return false;
    }


    //判断路径
    QString absFilePath=dir.absoluteFilePath(ui->lineEdit->text());//将第一个
    //text也拼接上来形成完整路径
    QDir dist_dir(absFilePath);
    if(dist_dir.exists()){
        ui->tips->setText("项目已存在!请更换路径或名字");
        return false;
    }

    ui->tips->setText("");//啥也不显示
    return QWizardPage::isComplete();//如果重写了基类的虚函数 
    后续还想再用其原本的功能 需要返回
}

✅ isComplete() 函数逻辑分解(用于向导页 ProSetPage)
🧩 步骤一:检查输入框是否为空
if (lineEdit->text() == “” || lineEdit_2->text() == “”) return false;
目的:
防止用户不填就跳转下一页,确保表单完整性
🗂️ 步骤二:验证路径是否存在
QDir dir(lineEdit_2->text());
if (!dir.exists()) {
tips->setText(“路径不存在!”);
return false;
}
目的:
及时阻止输入错误路径,避免后续操作失败。
📁 步骤三:判断项目目录是否已存在
QString absPath = dir.absoluteFilePath(lineEdit->text());
if (QDir(absPath).exists()) {
tips->setText(“项目已存在!请更换路径或名字”);
return false;
}
目的:
避免覆盖已有项目,确保创建路径唯一
如果路径不存在,我们就用absoluteFilePath将名字也拼接起来形成一个完整的路径
在这里插入图片描述

3.设置输入

我们打开注册这个界面的时候,我们的路径设置默认为当前路径
同时为输入设置光标 光标自动追到当前文本的最后

QString curPath=QDir::currentPath();
    ui->lineEdit_2->setText(curPath);//初始的默认路径为当前路径
    //设置光标
    ui->lineEdit_2->setCursorPosition(ui->lineEdit_2->text().size());

同时我们加入一个小图标,比如输入了一个很长的路径,发现错了,我们可以一键删除

//只要有输入 就能直接清除
    ui->lineEdit_2->setClearButtonEnabled(true);
    ui->lineEdit->setClearButtonEnabled(true);

在这里插入图片描述

4.实现浏览按钮

在这里插入图片描述
我们不仅可以让用户主动输入路径
也能点击目录 打开电脑下的目录直接选择
思路:
ui中选中此button点击转到槽
然后进行信号与槽的连接
实现一个槽函数即可

//浏览按钮
void ProSetPage::on_pushButton_clicked()
{
    QFileDialog file_dialog;
    file_dialog.setFileMode(QFileDialog::Directory);//设置为打开目录
    file_dialog.setWindowTitle(tr("选中存放的文件夹"));

    //默认打开路径
    QDir path=QDir::currentPath();
    file_dialog.setDirectory(path);//打开当前的文件
    file_dialog.setViewMode(QFileDialog::Detail);//以详细的信息方式显示

    QStringList list;//存放用户选中的
    if(file_dialog.exec()){
        list=file_dialog.selectedFiles();//用户选中的
    }

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

    QString apath=list.at(0);//第一个
    ui->lineEdit_2->setText(apath);

}

ProSetPage::on_pushButton_clicked() 浏览按钮点击事件详解
🧩 目的:
弹出文件夹选择对话框,让用户选择一个路径,并自动填入界面中的输入框lineEdit_2

✅ 第一步:创建并配置文件对话框

QFileDialog file_dialog;
file_dialog.setFileMode(QFileDialog::Directory);         // 设置为选择“目录”,不是文件
file_dialog.setWindowTitle(tr("选中存放的文件夹"));       // 设置窗口标题

🔎 解释:

QFileDialog 是 Qt 提供的文件对话框组件
setFileMode(QFileDialog::Directory) 表示:用户只能选择文件夹而不是文件
setWindowTitle 设置窗口的标题,tr() 是用于支持多语言

✅ 第二步:设置默认打开目录 + 视图样式

QDir path = QDir::currentPath();           // 获取当前工作目录
file_dialog.setDirectory(path);            // 设置默认打开路径为当前目录
file_dialog.setViewMode(QFileDialog::Detail); // 显示为详细信息模式

🔎 解释:
默认打开的是当前程序运行所在的路径(比如 D:\QtProject\Album\build);
Detail 视图让用户可以看到文件夹的详细信息(修改时间、大小等)

✅ 第三步:执行对话框并获取用户选择结果

QStringList list;//一个容器
if (file_dialog.exec()) {
    list = file_dialog.selectedFiles();    // 获取用户选中的文件夹列表
}

🔎 解释:
exec() 是以模态方式弹出文件选择窗口;
只有用户点“确定”后才会返回 true,然后用 selectedFiles() 拿到用户选择的路径;

✅ 第四步:判断是否选择了路径并更新输入框

if (list.length() <= 0) {
    return; // 用户没选就返回
}

QString apath = list.at(0); // 只取第一个路径
ui->lineEdit_2->setText(apath); // 显示到界面上

🔎 解释:
如果用户什么都没选就关闭对话框,就什么都不做;
如果选择了,就把路径显示在输入框 lineEdit_2 上;

在这里插入图片描述
此时点击浏览按钮
就会弹出目录框 然后可以选择文件,选中后自动更新在path的输入框中

(4)实现ConfirmPage.cpp

1.ui部分

在这里插入图片描述
在这里插入图片描述
运行起来就是这样,那么我们后续点击完成,我们要把前面输入的名字 路径都返回给主窗口,给ProTree类,ProTree类用来在MainWindow左侧显示树形目录,这个之后介绍
那么怎么返回呢?
我们重写QWizard中的done这个虚函数就行
在这里插入图片描述

2.重写done函数
//实现完成按钮
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);//如果重写了基类的虚函数 
    //后续还想再用其原本的功能 需要再次调用
}

三. 主窗口进入注册页面

 //连接信号与槽  创建项目
    connect(act_creat_pro,&QAction::triggered,this,&MainWindow::SlotCreatePro);

如果点击创建相册,就会触发我们绑定的信号与槽,接下来我们实现槽函数就行

void MainWindow::SlotCreatePro(bool)
{
    //qDebug()<<"slot create pro triggered"<<endl;
    Wizard wizard(this);//构造函数 父窗口设置为mainwindow
    wizard.setWindowTitle(tr("创建相册"));
    auto *page=wizard.page(0);//第一页
    page->setTitle(tr("相册名称与存放路径"));
    //连接信号与槽 把项目配置传回来todo
    connect(&wizard,&Wizard::SigProSettings,dynamic_cast<ProTree*>(_protree),&ProTree::AddProTree);
    wizard.resize(600,400);
    //展示
    wizard.show();
    wizard.exec();
    //断开所有信号todo
    disconnect();

}

所有源码我放入Github中同步更新
Github源码地址点击此处
后续持续更新…

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值