QT项目----电子相册(4)
文章目录
- 前言
- 一、右侧区域PicShow
- 1.创建PicShow
- 2.创建PicButton
- 3.效果图
- qss
- 4.设置动画
- QGraphicsOpacityEffect
- QPropertyAnimation
- 5.双击左侧图片目录 右侧显示图片
- 解决缩放时卡顿的问题
- 二、删除相册
- 实现思路
- 代码实现
- 总结
前言
提示:这里可以添加本文要记录的大概内容:
今天我们实现界面右侧的区域
主要功能就是双击左侧图片目录,右侧可以展示图片。两侧有按钮,可以上下切换图片,同时后期我们还准备做一个轮播图的效果,就是让相册照片自动播放
提示:以下是本篇文章正文内容,下面案例可供参考
一、右侧区域PicShow
1.创建PicShow
我们先创建一个界面类,然后绘制出一个界面
左右两侧是两个按钮,然后中间是一个Label,为了让Label居中,我用四个弹簧挤压居中
我们这里为两侧的按钮单独添加一个类PicButton然后将PicShow中按钮的类提升为我们自己自定义的类
然后将这个ui添加到主界面右侧
//右侧图片区_picshow=new PicShow();ui->picLayout->addWidget(_picshow);
2.创建PicButton
我们单独创建了一个类PicButton
然后我们想让这两个按钮上面有图像,并且有三种状态,一种正常状态,一种是鼠标悬浮在上面,一种是鼠标按下的状态,我们先准备好三种状态的图像,然后重写基类QPushButton的event函数即可
protected:bool event(QEvent *e) override;//通过这个事件e来判断是正常还是悬浮还是点击
bool PicButton::event(QEvent *e)
{switch(e->type()){case QEvent::Enter:setHoverIcon();break;case QEvent::Leave:setNormalIcon();break;case QEvent::MouseButtonPress:setPressedIcon();break;case QEvent::MouseButtonRelease:setHoverIcon();break;default:break;}return QPushButton::event(e);
}
这里的三种状态函数是我们之前写好的
#ifndef PICBUTTON_H
#define PICBUTTON_H#include <QPushButton>
#include<QPixmap>//加载图片样式
#include<QEvent>
class PicButton : public QPushButton
{
public:PicButton(QWidget *parent = nullptr);void SetIcon(const QString& normal,const QString& hover,const QString& pressed);//正常 悬浮 点击 时的按钮图片样式protected:bool event(QEvent *e) override;//通过这个事件e来判断是正常还是悬浮还是点击private:void setNormalIcon();//正常void setHoverIcon();//悬浮void setPressedIcon();//点击QString _normal;QString _hover;QString _pressed;
};#endif // PICBUTTON_H
void PicButton::setNormalIcon()
{QPixmap tmpPixmp;tmpPixmp.load(_normal);this->setIcon(tmpPixmp);}void PicButton::setHoverIcon()
{QPixmap tmpPixmp;tmpPixmp.load(_hover);this->setIcon(tmpPixmp);
}void PicButton::setPressedIcon()
{QPixmap tmpPixmp;tmpPixmp.load(_pressed);this->setIcon(tmpPixmp);
}
当确定状态后,我们就导入图片然后设置上去就行
这里是地址我们设置为了成员变量,并且在SetIcon函数中初始化了地址
void PicButton::SetIcon(const QString &normal, const QString &hover, const QString &pressed)
{_normal=normal;_hover=hover;_pressed=pressed;QPixmap tmpPixmp;tmpPixmp.load(normal);this->resize(tmpPixmp.size());this->setIcon(tmpPixmp);this->setIconSize(tmpPixmp.size());
}
这里我们一开始用this->resize(tmpPixmp.size());是将按钮大小设置为图片大小
后续的setIconSize 是设置此图标在按钮中显示的大小!
3.效果图
这里我们用了qss来将这个图标的边距弄成0 更好看
qss
#nextBtn,#previousBtn {border: 0px;
}
4.设置动画
我们不想这两个图标一直显示出来,我想当鼠标移动到右侧区域的时候,两个图标逐渐显示出来,当鼠标转移至左侧区域的时候,图标逐渐隐藏
QGraphicsOpacityEffect
QGraphicsOpacityEffect 是 Qt 框架中用于实现控件透明度(不透明度)效果的一个类,常用于制作淡入淡出、渐隐渐现等视觉效果。
📌 基本介绍
类名:QGraphicsOpacityEffect
所在模块:QtWidgets
作用:为控件(如 QWidget)添加不透明度效果,控制其显示的透明程度。
🌟 关键方法
方法 说明
setOpacity(double opacity) 设置不透明度,范围为 0.0(完全透明) 到 1.0(完全不透明)
我们这里先创建两个透明度0,然后将按钮设置为该透明度
QGraphicsOpacityEffect* opacity_pre=new QGraphicsOpacityEffect(this);opacity_pre->setOpacity(0);//设置透明度QGraphicsOpacityEffect* opacity_next=new QGraphicsOpacityEffect(this);opacity_next->setOpacity(0);//设置透明度ui->previousBtn->setGraphicsEffect(opacity_pre);//左侧按钮ui->nextBtn->setGraphicsEffect(opacity_next);//右侧按钮
此时按钮的透明度为0 相当于消失的状态
QPropertyAnimation
QPropertyAnimation 是 Qt 动画框架中的一个核心类,用于对对象的属性进行平滑动画过渡。它支持对 QObject 派生类的属性进行线性或非线性变化,比如位置、大小、颜色、不透明度等。
📌 基本介绍
类名:QPropertyAnimation
模块:QtCore(但常用于 QtWidgets)
作用:让某个属性在一段时间内从一个值平滑过渡到另一个值。
🔧 常用构造函数
QPropertyAnimation(QObject *target, const QByteArray &propertyName);
target:动画作用的对象
propertyName:要改变的属性,比如 “geometry”, “pos”, “opacity” 等
🌟 常用方法
方法 说明
setDuration(int msecs) 设置动画持续时间(单位:毫秒)
setStartValue(const QVariant &value) 起始值
setEndValue(const QVariant &value) 结束值
setEasingCurve(QEasingCurve::Type) 设置缓动曲线(控制动画速度变化,比如匀速、加速等)
start() 启动动画
这里我们为两个按钮都单独设置一个动画,动画状态设置为线性平稳
时间为500ms
_animation_show_pre=new QPropertyAnimation(opacity_pre,"opacity",this);_animation_show_pre->setEasingCurve(QEasingCurve::Linear);_animation_show_pre->setDuration(500);//动画时长_animation_show_next=new QPropertyAnimation(opacity_next,"opacity",this);_animation_show_next->setEasingCurve(QEasingCurve::Linear);_animation_show_next->setDuration(500);//动画时长
现在准备工作已经完成,我们重写event函数就行,判断当前鼠标的位置,如果进入右侧区域,我们就让按钮显示,离开的时候我们就让按钮消失就行
bool PicShow::event(QEvent *event)//如果进入这个页面
{switch(event->type()){case QEvent::Enter:ShowPreNextBtns(true);break;case QEvent::Leave:ShowPreNextBtns(false);break;default:break;}return QDialog::event(event);
}
这里的ShowPreNextBtns是我们自定义的一个函数
void PicShow::ShowPreNextBtns(bool b_show)//
{//此时鼠标离开这个页面 并且按键是出现的if(!b_show&&_b_show)//显示状态------>隐藏状态{_animation_show_pre->stop();_animation_show_pre->setStartValue(1);_animation_show_pre->setEndValue(0);_animation_show_pre->start();_animation_show_next->stop();_animation_show_next->setStartValue(1);_animation_show_next->setEndValue(0);_animation_show_next->start();_b_show=false;//按钮已经隐藏return;}//此时鼠标在这个页面 并且按键是隐藏的if(b_show&&!_b_show)//隐藏状态------>显示状态{_animation_show_pre->stop();_animation_show_pre->setStartValue(0);_animation_show_pre->setEndValue(1);_animation_show_pre->start();_animation_show_next->stop();_animation_show_next->setStartValue(0);_animation_show_next->setEndValue(1);_animation_show_next->start();_b_show=true;//按钮已经隐藏return;}
}
思路就是当鼠标进入一个状态后,我们先让之前动画状态停止stop,然后在设置起始值,再开始就行
5.双击左侧图片目录 右侧显示图片
我们先在ProTreeWidget中写一个函数,如果是左键双击一个图片,不是目录,我们就传送一个信号,并且将图片地址传过去
void ProTreeWidget::SlotDoubleClickItem(QTreeWidgetItem *doubleitem, int col)
{if(QGuiApplication::mouseButtons()== Qt::LeftButton){auto * tree_double =dynamic_cast<ProTreeItem*>(doubleitem);if(!tree_double){return;}int itemtype=tree_double->type();if(itemtype==TreeItemPic){emit SigUpdateSelected(tree_double->GetPath());_selected_item=doubleitem;}}
}
然后发送的信号我们在主界面MainWindow中连接
auto * pro_picshow=dynamic_cast<PicShow*>(_picshow);connect(treewidget,&ProTreeWidget::SigUpdateSelected,pro_picshow,&PicShow::SlotSelectItem);
现在我们实现PicShow中的这个槽函数就行
void PicShow::SlotSelectItem(const QString &path)
{_select_path=path;//图片的地址_pix_map.load(path);auto width=this->width();auto height=this->height();_pix_map=_pix_map.scaled(width,height,Qt::KeepAspectRatio);ui->label->setPixmap(_pix_map);
}
因为图片传入进来,我们不确定宽高是否合适,我们就获取展示界面的宽高,然后对图片进行缩放
auto width=this->width();
auto height=this->height();
_pix_map=_pix_map.scaled(width,height,Qt::KeepAspectRatio);
Qt::KeepAspectRatio 参数表示缩放时保持图片比例。
但在对程序进行拉伸,缩小,放大的过程中,可能会使图片比例发生变化
我们写一个重绘事件,并且在MainWindow中调用
void PicShow::ReloadPic()//重绘
{if(_select_path!=""){const auto&width=ui->gridLayout->geometry().width();//获取矩形区域的宽const auto&height=ui->gridLayout->geometry().height();_pix_map.load(_select_path);_pix_map=_pix_map.scaled(width,height,Qt::KeepAspectRatio);ui->label->setPixmap(_pix_map);}
}
ui->gridLayout
gridLayout 是你在 Qt Designer 中放的一个 栅格布局控件(QGridLayout),负责布局其他控件
相当于获取了一个整体可视区域
geometry()
返回一个 QRect 类型,表示这个控件(或布局)在父控件中的几何区域。
包括位置 (x, y) 和尺寸 (width, height)
void MainWindow::resizeEvent(QResizeEvent *event)//重绘事件
{auto *pro_pic_show=dynamic_cast<PicShow*>(_picshow);pro_pic_show->ReloadPic();QMainWindow::resizeEvent(event);
}
解决缩放时卡顿的问题
因为我们在缩放的时候,我们每一次都要对图片进行重绘,导致卡顿,这里我们一开始保存第一张原图,然后重绘的时候,对第一张原图进行重绘就行
这是首次双击左侧的时候,加载进来的第一张原图
void PicShow::SlotSelectItem(const QString &path)//首次图片
{// _select_path=path;// _pix_map.load(path);// auto width=this->width();// auto height=this->height();// _pix_map=_pix_map.scaled(width,height,Qt::KeepAspectRatio);// ui->label->setPixmap(_pix_map);_select_path = path;if(Original_map.load(path)){DisplayUpdate();}
}
调用更新的函数
void PicShow::DisplayUpdate()//更新状态
{auto width=ui->gridLayout->geometry().width();auto height=ui->gridLayout->geometry().height();_pix_map=Original_map.scaled(width,height,Qt::KeepAspectRatio);ui->label->setPixmap(_pix_map);
}
然后在缩放进行重绘的时候
MainWindow中调用重绘函数
void MainWindow::resizeEvent(QResizeEvent *event)//重绘事件
{auto *pro_pic_show=dynamic_cast<PicShow*>(_picshow);pro_pic_show->ReloadPic();return QMainWindow::resizeEvent(event);
}
void PicShow::ReloadPic()//重绘
{// if(_select_path!="")// {// const auto&width=ui->gridLayout->geometry().width();//获取矩形区域的宽// const auto&height=ui->gridLayout->geometry().height();// _pix_map.load(_select_path);// _pix_map=_pix_map.scaled(width,height,Qt::KeepAspectRatio);// ui->label->setPixmap(_pix_map);// }if (!Original_map.isNull()) {DisplayUpdate();}
}
二、删除相册
我们之前完成了导入相册,设置此相册为活动相册,删除相册,我们现在完成删除相册的后部分
在删除相册的时候,如果此时右侧打开的照片属于我们要删除的相册的话,我们还需要清除右侧的图片
实现思路
我们在之前删除相册的函数中判断,先获取右侧图片所显示的照片的根目录,如果与删除的相册根目录相同,我们就发送一个信号通知,要将右侧的图清除掉,同时将保存图片的成员变量和地址都设置为空
代码实现
判断+发送信号
//如果关闭了相册 此时右侧还显示相册中图片 那我们要清除auto *selectitem=dynamic_cast<ProTreeItem*>(_selected_item);//qDebug() << "_selected_item is null?" << (_selected_item == nullptr);//qDebug() << "selectitem is null?" << (selectitem == nullptr);if(selectitem&&now_tree_item==selectitem->GetRoot()){selectitem=nullptr;_selected_item=nullptr;emit SigClearPicShow();//qDebug()<<"fa";}
连接信号
connect(treewidget,&ProTreeWidget::SigClearPicShow,pro_picshow,&PicShow::SlotClearnow);
实现函数
void PicShow::SlotClearnow()
{_select_path="";Original_map=QPixmap();_pix_map=QPixmap();if(ui->label){ui->label->clear();}// qDebug() << "SlotClearnow called, _select_path = " << _select_path;}
总结
接下来我们把后续的轮播图做完就好了
所有代码包括qss的代码我都同步更新在GitHub仓库中
点击此处