QT 实现电子相册(五)--实现幻灯片的暂停和切换

状态切换按钮

我们之前制作过按钮类为PicButton,但是这次我们要制作另外一个按钮类,主要是实现状态切换,比如当前是播放状态,那么按钮就显示出暂停的图标,点击暂停后切换为播放的图标。同时还要支持滑动,点击,正常的三种效果。
PicStateBtn构造函数

  1. PicStateBtn::PicStateBtn(QWidget *parent ):QPushButton (parent){
  2. }

添加一个函数设置播放状态和暂停状态的图标

  1. void PicStateBtn::SetIcons(const QString &normal, const QString &hover, const QString &pressed,
  2. const QString &normal_2, const QString &hover_2, const QString &pressed_2)
  3. {
  4. _normal = normal;
  5. _hover = hover;
  6. _pressed = pressed;
  7. _normal_2 = normal_2;
  8. _hover_2 = hover_2;
  9. _pressed_2 = pressed_2;
  10. QPixmap tmpPixmap;
  11. tmpPixmap.load(normal);
  12. this->resize(tmpPixmap.size());
  13. this->setIcon(tmpPixmap);
  14. this->setIconSize(tmpPixmap.size());
  15. _cur_state = PicBtnStateNormal;
  16. }

normal,hover,pressed分别表示播放状态正常,悬浮,点击的效果。
_normal_2,_hover_2,_pressed_2分别表示暂停状态正常,悬浮,点击的效果。
_cur_state表示现在是上述六种状态的哪一种,具体定义在const.h文件里

  1. enum PicBtnState {
  2. PicBtnStateNormal = 1,
  3. PicBtnStateHover = 2,
  4. PicBtnStatePress = 3,
  5. PicBtnState2Normal = 4,
  6. PicBtnState2Hover = 5,
  7. PicBtnState2Press = 6,
  8. };

对应的我们实现了六种状态的加载函数

  1. void PicStateBtn::setNormalIcon(){
  2. qDebug()<<"setNormalIcon _normal " << _normal << endl;
  3. QPixmap tmpPixmap;
  4. tmpPixmap.load(_normal);
  5. this->setIcon(tmpPixmap);
  6. _cur_state = PicBtnStateNormal;
  7. }
  8. void PicStateBtn::setHoverIcon(){
  9. qDebug()<<"setHoverIcon _hover " << _hover << endl;
  10. QPixmap tmpPixmap;
  11. tmpPixmap.load(_hover);
  12. this->setIcon(tmpPixmap);
  13. _cur_state = PicBtnStateHover;
  14. }
  15. void PicStateBtn::setPressIcon(){
  16. qDebug()<<"setPressIcon _pressed " << _pressed << endl;
  17. QPixmap tmpPixmap;
  18. tmpPixmap.load(_pressed);
  19. this->setIcon(tmpPixmap);
  20. _cur_state = PicBtnStatePress;
  21. }
  22. void PicStateBtn::setNormal2Icon()
  23. {
  24. qDebug()<<"setPressIcon _normal_2 " << _normal_2 << endl;
  25. QPixmap tmpPixmap;
  26. tmpPixmap.load(_normal_2);
  27. this->setIcon(tmpPixmap);
  28. _cur_state = PicBtnState2Normal;
  29. }
  30. void PicStateBtn::setHover2Icon()
  31. {
  32. qDebug()<<"setPressIcon _hover_2 " << _hover_2 << endl;
  33. QPixmap tmpPixmap;
  34. tmpPixmap.load(_hover_2);
  35. this->setIcon(tmpPixmap);
  36. _cur_state = PicBtnState2Hover;
  37. }
  38. void PicStateBtn::setPress2Icon()
  39. {
  40. qDebug()<<"setPressIcon _pressed_2 " << _pressed_2 << endl;
  41. QPixmap tmpPixmap;
  42. tmpPixmap.load(_pressed_2);
  43. this->setIcon(tmpPixmap);
  44. _cur_state = PicBtnState2Press;
  45. }

接下来实现鼠标滑动,点击,以及正常效果的切换,我们重写event

  1. bool PicStateBtn::event(QEvent *event)
  2. {
  3. switch (event->type())
  4. {
  5. case QEvent::Enter:
  6. if(_cur_state < PicBtnState2Normal){
  7. setHoverIcon();
  8. }else{
  9. setHover2Icon();
  10. }
  11. break;
  12. case QEvent::Leave:
  13. if(_cur_state < PicBtnState2Normal){
  14. setNormalIcon();
  15. }else{
  16. setHover2Icon();
  17. }
  18. break;
  19. case QEvent::MouseButtonPress:
  20. if(_cur_state < PicBtnState2Normal){
  21. setPressIcon();
  22. }else{
  23. setPress2Icon();
  24. }
  25. break;
  26. case QEvent::MouseButtonRelease:
  27. if(_cur_state < PicBtnState2Normal){
  28. setHover2Icon();
  29. }else{
  30. setHoverIcon();
  31. }
  32. break;
  33. default:
  34. break;
  35. }
  36. return QPushButton::event(event);
  37. }

上述根据现在是播放状态还是暂停状态,再根据鼠标事件设置图标。
另外我们需要实现开始和暂停的切换效果,所以新增两个槽函数

  1. void PicStateBtn::SlotStart()
  2. {
  3. setNormal2Icon();
  4. }
  5. void PicStateBtn::SlotStop()
  6. {
  7. setNormalIcon();
  8. }

我们回到SlideShowDlg.ui文件,将playBtn升级为PicStateBtn。
然后在SlideShowDlg的构造函数里为按钮设置图标,并且将PicAnimationWid的SigStart和SigStop信号与之连接起来

  1. ui->playBtn->SetIcons(":/icon/play.png",":/icon/play_hover.png",":/icon/play_press.png",
  2. ":/icon/pause.png",":/icon/pause_hover.png",":/icon/pause_press.png");
  3. //连接动画和按钮显示状态
  4. connect(ui->picAnimation,&PicAnimationWid::SigStart, ui->playBtn, &PicStateBtn::SlotStart);
  5. connect(ui->picAnimation,&PicAnimationWid::SigStop, ui->playBtn, &PicStateBtn::SlotStop);

这样动画一开始按钮就被设置为暂停图标,表示动画正在运行,点击暂停图标又会切换为运行图标,表示动画已经暂停。

关闭按钮

SlideShowDlg的关闭按钮比较影响体验,我们隐藏边框上的按钮,在构造函数里添加

  1. this->setWindowFlags(Qt::Dialog|Qt::FramelessWindowHint);

升级SlideShowDlg的ui文件中的closeBtn为PicButton,并且在构造函数里添加加载图标的逻辑和信号连接。

  1. ui->closeBtn->SetIcons(":/icon/closeshow.png",":/icon/closeshow_hover.png",
  2. ":/icon/closeshow_press.png");
  3. //连接关闭按钮
  4. connect(ui->closeBtn, &QPushButton::clicked, this, &SlideShowDlg::close);

这样就能响应关闭按钮的事件了。

切换跳转

我们需要点击向前和向后按钮,实现动画图片的切换,这里先升级SlideShowDlg的ui文件中的slidenextBtn和slidpreBtn按钮为PicButton
然后在构造函数添加加载逻辑和信号连接

  1. ui->slidpreBtn->SetIcons(":/icon/previous.png",
  2. ":/icon/previous_hover.png",
  3. ":/icon/previous_press.png");
  4. ui->slidenextBtn->SetIcons(":/icon/next.png",
  5. ":/icon/next_hover.png",
  6. ":/icon/next_press.png");
  7. //连接向后查看按钮
  8. connect(ui->slidenextBtn, &QPushButton::clicked,this,&SlideShowDlg::SlotSlideNext);
  9. //连接向前查看按钮
  10. connect(ui->slidpreBtn, &QPushButton::clicked,this,&SlideShowDlg::SlotSlidePre);

这两个槽函数内部调用了PicAnimationWid的SlideNext和SlidePre

  1. void SlideShowDlg::SlotSlideNext()
  2. {
  3. ui->picAnimation->SlideNext();
  4. }
  5. void SlideShowDlg::SlotSlidePre()
  6. {
  7. ui->picAnimation->SlidePre();
  8. }

PicAnimationWid的两个函数分别实现图片的切换

  1. void PicAnimationWid::SlideNext()
  2. {
  3. Stop();
  4. if(!_cur_item){
  5. return;
  6. }
  7. auto * cur_pro_item = dynamic_cast<ProTreeItem*>(_cur_item);
  8. auto * next_item = cur_pro_item->GetNextItem();
  9. if(!next_item){
  10. return;
  11. }
  12. SetPixmap(next_item);
  13. update();
  14. }
  15. void PicAnimationWid::SlidePre()
  16. {
  17. Stop();
  18. if(!_cur_item){
  19. return;
  20. }
  21. auto * cur_pro_item = dynamic_cast<ProTreeItem*>(_cur_item);
  22. auto * pre_item = cur_pro_item->GetPreItem();
  23. if(!pre_item){
  24. return;
  25. }
  26. SetPixmap(pre_item);
  27. update();
  28. }

切换后动画暂停,变为显示图片的状态。
为了美观,我们完善一下qss

  1. #preListWidget {
  2. color:rgb(231,231,231);
  3. background-color:rgb(46,47,48);
  4. border: 0px;
  5. }
  6. #preListWidget::item:hover {
  7. background: rgb(38, 95, 153);
  8. }
  9. #preListWidget::item:selected {
  10. background: rgb(38, 95, 153);
  11. }
  12. #slidpreBtn,#slidenextBtn,#playBtn {
  13. border: 0px;
  14. }
  15. #slideprewid {
  16. margin-left:10px;
  17. }
  18. #slidenextwid{
  19. margin-right:10px;
  20. }
  21. #preListWidget::item:selected:active{
  22. border: 2px solid #FFFFFF;
  23. }
  24. #preListWidget::item:selected{
  25. border: 2px solid #FFFFFF;
  26. }

将按钮设置为无边框,然后设置了preListWidget的边框和边距等信息。

添加音乐

为了让动画播放过程中能够播放音乐,我们在mainwindow的菜单里添加音乐菜单。

  1. //设置背景音乐动作
  2. QAction * act_music = new QAction(QIcon(":/icon/music.png"), tr("背景音乐"),this);
  3. act_music->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_M));
  4. menu_set->addAction(act_music);
  5. //设置音乐
  6. connect(act_music, &QAction::triggered, pro_tree_widget, &ProTreeWidget::SlotSetMusic);

在打开音乐的槽函数里弹出一个文件夹对话框

  1. void ProTreeWidget::SlotSetMusic(bool)
  2. {
  3. qDebug() << "SlotSetMusic" <<endl;
  4. QFileDialog file_dialog;
  5. file_dialog.setFileMode(QFileDialog::ExistingFiles);
  6. file_dialog.setWindowTitle("选择导入的文件夹");
  7. file_dialog.setDirectory(QDir::currentPath());
  8. file_dialog.setViewMode(QFileDialog::Detail);
  9. file_dialog.setNameFilter("(*.mp3)");
  10. QStringList fileNames;
  11. if (file_dialog.exec()){
  12. fileNames = file_dialog.selectedFiles();
  13. }
  14. if(fileNames.length() <= 0){
  15. return;
  16. }
  17. _playlist->clear();
  18. for(auto filename : fileNames){
  19. qDebug() << "filename is " << filename << endl;
  20. _playlist->addMedia(QUrl::fromLocalFile(filename));
  21. }
  22. if(_player->state()!=QMediaPlayer::PlayingState)
  23. {
  24. _playlist->setCurrentIndex(0);
  25. }
  26. }

文件夹对话框返回选择的文件列表,我们将文件列表加入播放列表_playlist。然后通过判断_player的状态设置索引。
_player为QMediaPlayer类型,_playlist为QMediaPlaylist类型,我们需要在pro里添加multimedia才能使用。

  1. QT += core gui multimedia

另外要在protreewidget头文件包含

  1. #include<QtMultimedia/QMediaPlayer>
  2. #include<QtMultimedia/QMediaPlaylist>

然后在SlideShowDlg的构造函数添加播放音乐和停止音乐的槽函数

  1. //连接音乐启动信号
  2. connect(ui->picAnimation, &PicAnimationWid::SigStartMusic, _protree_widget,
  3. &ProTreeWidget::SlotStartMusic);
  4. //连接音乐关闭信号
  5. connect(ui->picAnimation,&PicAnimationWid::SigStopMusic, _protree_widget,
  6. &ProTreeWidget::SlotStopMusic);

播放音乐和停止音乐逻辑很简单

  1. void ProTreeWidget::SlotStartMusic()
  2. {
  3. qDebug()<< "ProTreeWidget::SlotStartMusic" << endl;
  4. _player->play();
  5. }
  6. void ProTreeWidget::SlotStopMusic()
  7. {
  8. qDebug()<< "ProTreeWidget::SlotStopMusic" << endl;
  9. _player->pause();
  10. }

到此为止就完成了动画播放的所有逻辑,这里是整体效果图
https://cdn.llfc.club/1675153305157.jpg

源码链接

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

热门评论

热门文章

  1. 解密定时器的实现细节

    喜欢(566) 浏览(1674)
  2. C++ 类的继承封装和多态

    喜欢(588) 浏览(2333)
  3. slice介绍和使用

    喜欢(521) 浏览(1582)
  4. Linux环境搭建和编码

    喜欢(594) 浏览(5006)
  5. windows环境搭建和vscode配置

    喜欢(587) 浏览(1658)

最新评论

  1. C++ 线程管控 secondtonone1:好的,已修复,写的时候马虎了,谢谢指正。
  2. C++ 面试常问问题 secondtonone1:谢谢,你说的对,将基类设置为虚析构即可
  3. 线程基础 樊南七:char const *不是指针常量,char const *=const char*常量指针,不可修改值,可以修改地址。而你说的指针常量怎么可能修改地址,只能修改值
  4. 面试题汇总(一) secondtonone1:看到网络上经常提问的go的问题,做了一下汇总,结合自己的经验给出的答案,如有纰漏,望指正批评。
  5. 创建项目和编译 secondtonone1:谢谢支持

个人公众号

个人微信