图片浏览器逻辑

  实现图片浏览器用到了前面几乎所有的知识,包括窗口部件、布局、事件、对象模型与容器类、图形视图、模型/视图编程以及多线程等。大致流程为:首先定义一个图片类,该类包含图片的路径、文件名、文件id以及获取这些变量的函数。然后定义了一个图片数组类,主要包含添加图像以及获取所有图像以及新加入图像的函数。最后通过将图片名字加入到界面左侧QDockWidget部件中的QTreeView中,通过线程将图片的预览加入界面下侧的窗口部件中。最后通过双击可查看完整图片,以及通过滚轮和鼠标等事件来对图片进行一些操作。

效果图

具体实现

utils.h

#ifndef UTILS_H
#define UTILS_H#include<QString>
#include<string>//string to QString
inline QString str2qstr(const std::string& str)
{return QString::fromLocal8Bit(str.data());
}//QString to string
inline std::string qstr2str(const QString& qstr)
{QByteArray cdata = qstr.toLocal8Bit();return std::string(cdata);
}#endif // UTILS_H

image.h

#ifndef IMAGE_H
#define IMAGE_H
#include<string>
#include<vector>using std::vector;
using std::string;class Image
{public:Image() = default;~Image() = default;Image(const string& _path,const unsigned& _id):path_(_path),id_(_id){//从路径中获取图像名称auto pos = path_.find_last_of('\\') +1;if(pos == 0){pos = path_.find_last_of('/')+1;}name_ = path_.substr(pos,path_.length() - pos);pos = name_.find_last_of('.');name_ = name_.substr(0,pos);}//设置相机所属的idvoid set_cam_id(const unsigned& _id){cam_id_ = _id;}//获取路径const string& get_path(){return path_;}//获取文件名const string& get_name(){return name_;}const unsigned &get_id(){return id_;}//获取相机idconst unsigned& get_cam_id(){return cam_id_;}private:string path_;string name_;unsigned id_;unsigned cam_id_;
};#endif // IMAGE_H

image_group.h

#ifndef IMAGE_GROUP_H
#define IMAGE_GROUP_H
#include"image.h"class image_group
{public:image_group();~image_group();public:bool addImages(const vector<string>& img_paths);const vector<Image>& GetAllImages();const vector<Image>& GetNewAddingImages();private://所有图片数组vector<Image> all_images_;//新加入的图片数组vector<Image> new_images_;
};#endif // IMAGE_GROUP_H

image_group.cpp

#include "image_group.h"image_group::image_group()
{}image_group::~image_group()
{}bool image_group::addImages(const vector<std::string> &img_paths)
{new_images_.clear();for(auto& path: img_paths){all_images_.emplace_back(path,all_images_.size());new_images_.emplace_back(path,all_images_.size());}return true;
}const vector<Image> &image_group::GetAllImages()
{return all_images_;
}const vector<Image> &image_group::GetNewAddingImages()
{return new_images_;
}

qimgviewwidget.h

#ifndef QIMGVIEWWIDGET_H
#define QIMGVIEWWIDGET_H#include <QWidget>
#include<QImage>//用于显示2D图像的窗口部件
class QImgViewWidget : public QWidget
{Q_OBJECT
public:explicit QImgViewWidget(QWidget *parent = nullptr);~QImgViewWidget() = default;//从文件路径加载图片void SetImage(const QString& img_path);void ResetTransform();private://用来展示的image信息QImage img_display_;//原始pixmap信息QPixmap pix_ori_;//用来展示的pixmap信息QPixmap pix_display_;//图片路径QString img_path_;//鼠标滚轮控制的缩放比例float zoom_scale_;//由鼠标移动控制的移动QPoint move_step_;bool move_start_;bool is_moving_;QPoint mouse_point_;protected:void paintEvent(QPaintEvent* event)override;void wheelEvent(QWheelEvent* event)override;void mousePressEvent(QMouseEvent* event)override;void mouseReleaseEvent(QMouseEvent* event)override;void mouseMoveEvent(QMouseEvent* event)override;void resizeEvent(QResizeEvent* event)override;};#endif // QIMGVIEWWIDGET_H

qimgviewwidget.cpp

#include "qimgviewwidget.h"
#include <QPainter>
#include <QWheelEvent>QImgViewWidget::QImgViewWidget(QWidget *parent) : QWidget(parent)
{zoom_scale_ = 1.0f;move_start_ = false;is_moving_ = false;
}void QImgViewWidget::SetImage(const QString &img_path)
{ResetTransform();QSize view_size = size();//通过QImage加载图像img_path_ = img_path;img_display_.load(img_path_);pix_ori_ = QPixmap::fromImage(img_display_);pix_display_ = pix_ori_.scaled(zoom_scale_ *size(),Qt::KeepAspectRatio);}void QImgViewWidget::ResetTransform()
{//重新设置缩放比例和移动位置zoom_scale_ = 1.0f;move_step_ = QPoint(0,0);
}void QImgViewWidget::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(move_step_.x()+(width()-pix_display_.width())/2,move_step_.y()+(height()- pix_display_.height()) / 2,pix_display_);
}void QImgViewWidget::wheelEvent(QWheelEvent *event)
{//随滚轮缩放if(event->delta()>0){zoom_scale_ *= 1.1;}else {zoom_scale_ *=0.9;}pix_display_ = pix_ori_.scaled(zoom_scale_ * size(),Qt::KeepAspectRatio);update();
}void QImgViewWidget::mousePressEvent(QMouseEvent *event)
{if(event->button() == Qt::LeftButton){if(!move_start_){move_start_ = true;is_moving_ = false;mouse_point_ = event->globalPos();}}
}void QImgViewWidget::mouseReleaseEvent(QMouseEvent *event)
{if(event->button() ==Qt::LeftButton){if(move_start_){move_start_ = false;is_moving_ = false;}}
}void QImgViewWidget::mouseMoveEvent(QMouseEvent *event)
{if(move_start_){const QPoint mos_pt = event->globalPos();move_step_ +=mos_pt - mouse_point_;is_moving_ = true;mouse_point_ = mos_pt;repaint();}
}void QImgViewWidget::resizeEvent(QResizeEvent *event)
{pix_display_ = pix_ori_.scaled(zoom_scale_ *size(),Qt::KeepAspectRatio);update();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include"image_group.h"
#include<QThread>
namespace Ui {class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = Q_NULLPTR);
//    ~MainWindow();image_group* get_image_group(){return &image_group_;}Ui::MainWindow* get_ui(){return ui;}void InitTreeView();void InitPrewView();void InitDockView();void InitTabView();void InitLayout();void updateTreeView();void updatePreView();private slots:void OnActionAddImages();void OnActiondoubleClickedTreeImage(const QModelIndex& index);protected:void paintEvent(QPaintEvent* event)override;void resizeEvent(QResizeEvent* event)override;private:Ui::MainWindow *ui;image_group image_group_;};class QUpdatePreviewThread :public QThread
{Q_OBJECTpublic:QUpdatePreviewThread(MainWindow* mainwindow);
signals:void SingalAddPreview(const QPixmap& pixmap,const int& img_id);private slots:void SlotAddPreview(const QPixmap& pixmap,const int& img_id);protected:void run() override;
private:MainWindow* mainwindow_;};#endif // MAINWINDOW_H

mainwindow.cpp

#include"utils.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QStandardItemModel>
#include<QFileDialog>
#include<QMessageBox>
#include<QResizeEvent>
#include<QListWidgetItem>
#include<QImageReader>MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setWindowState(Qt::WindowMaximized);//初始化UiInitDockView();InitTreeView();InitTabView();InitPrewView();InitLayout();connect(ui->action_addimages,&QAction::triggered,this,&MainWindow::OnActionAddImages);connect(ui->tree_images,&QTreeView::doubleClicked,this,&MainWindow::OnActiondoubleClickedTreeImage);connect(ui->list_previews,&QTreeView::doubleClicked,this,&MainWindow::OnActiondoubleClickedTreeImage);
}void MainWindow::InitTreeView()
{//初始化tree viewauto tree_imgs = ui->tree_images;auto* model = new QStandardItemModel(tree_imgs);tree_imgs->setModel(model);model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("images"));tree_imgs->setEditTriggers(QAbstractItemView::NoEditTriggers);
}void MainWindow::InitPrewView()
{//初始化preview viewauto list_preview = ui->list_previews;list_preview->setIconSize(QSize(100,100));list_preview->setResizeMode(QListView::Adjust);list_preview->setViewMode(QListView::IconMode);list_preview->setMovement(QListView::Static);list_preview->setSpacing(10);}void MainWindow::InitDockView()
{//初始化dockViewauto dp_workspace = (QDockWidget*)ui->dock_workspace;dp_workspace->setWindowTitle("Wokspace");addDockWidget(Qt::LeftDockWidgetArea,dp_workspace);
}void MainWindow::InitTabView()
{//2d/3d部件的样式表
//    auto tab_view = ui->tab_mainview;
//    tab_view->setStyleSheet("QTabWidget:pane{ border: 1px ;}\
//                                QTabBar::tab{width:50px;height:28px; background-color:rgb(36,36,36); color:rgb(200,200,200); margin-right: 2px; margin-bottom:-2px;}\
//                                QTabBar::tab:selected{border:1px;border-bottom-color: none; background-color:rgb(50,50,50)}\
//                                QTabBar::tab:!selected{border-bottom: 3px;}\
//                            ");
//    tab_view->setCurrentIndex(0);//    auto wid_model = ui->widget_model;
//    wid_model->setStyleSheet("background-color:rgb(80,80,80);");//    auto wid_image = ui->widght_imgview;
//    wid_image->setStyleSheet(" background-color:rgb(80,80,80);");//    //照片/控制台部件样式表
//    auto tab_info = ui->tab_info;
//    tab_info->setStyleSheet("QTabWidget:pane{ border: 1px ;}\
//                                QTabBar::tab{width:60px;height:28px; background-color:rgb(36,36,36); color:rgb(200,200,200); margin-right: 2px; margin-bottom:-2px;}\
//                                QTabBar::tab:selected{border:1px;border-bottom-color: none; background-color:rgb(50,50,50)}\
//                                QTabBar::tab:!selected{border-bottom: 3px;}\
//                            ");
//    auto wid_priviews = ui->widget_previews;
//    wid_priviews->setStyleSheet(" background-color:rgb(80,80,80);");//    auto wid_console = ui->widget_console;
//    wid_console->setStyleSheet(" background-color:rgb(80,80,80);");
}void MainWindow::InitLayout()
{}void MainWindow::updateTreeView()
{//相关操作后更新tree view。例如,加载图像const auto all_images = image_group_.GetAllImages();const auto new_images = image_group_.GetNewAddingImages();if(new_images.empty())return;const auto num_allimages = all_images.size();const auto num_images = new_images.size();auto* tree = ui->tree_images;auto* model = static_cast<QStandardItemModel*>(tree->model());QString str_title = QString("All Images (%1 Images)").arg(num_allimages);if(model->item(0,0) ==nullptr){model->setItem(0,0,new QStandardItem(str_title));}else {auto item = model->item(0,0);item->setText(str_title);}//为tree添加图片的名字for(auto image:new_images){model->item(0,0)->setChild(image.get_id(),0,new QStandardItem(str2qstr(image.get_name())));}tree->setExpanded(model->index(0,0),true);auto workspace = static_cast<QDockWidget*>(ui->dock_workspace);auto ws_size = workspace->frameSize();tree->setFixedWidth(ws_size.width());}void MainWindow::updatePreView()
{auto tab_info = ui->tab_info;tab_info->setCurrentIndex(0);//通过线程来创建previewsQUpdatePreviewThread* thread = new QUpdatePreviewThread(this);thread->start();}void MainWindow::OnActionAddImages()
{QStringList file_paths = QFileDialog::getOpenFileNames(this,tr("Image Path"),"Data\\", tr("Image Files(*png *jpg *tif);"));//添加图片vector<string> str_paths;for(auto path:file_paths){str_paths.push_back(qstr2str(path));}image_group_.addImages(str_paths);//更新tree viewupdateTreeView();//更新preview viewupdatePreView();}void MainWindow::OnActiondoubleClickedTreeImage(const QModelIndex &index)
{QMessageBox msg_box;auto* tree = ui->tree_images;auto* model = static_cast<QStandardItemModel*>(tree->model());unsigned img_id = index.row();const auto all_images = image_group_.GetAllImages();if(img_id>=all_images.size()){msg_box.setText("data error");msg_box.exec();return;}//获得双击的图片路径auto image = all_images[img_id];auto imgpath = str2qstr(image.get_path());//repaintauto img_view = ui->widght_imgview;img_view->SetImage(imgpath);img_view->repaint();}void MainWindow::paintEvent(QPaintEvent* event)
{}void MainWindow::resizeEvent(QResizeEvent* event)
{//自动调整所有小部件的大小const QSize size = event->size();const QRect frame_geometry = ui->central_widget->geometry();const QSize frame_size = ui->central_widget->size();const QSize menu_size = ui->menuBar->size();QSize layout_h1(menu_size.width() * 0.12, frame_size.height()),layout_h2(menu_size.width() * 0.76, frame_size.height()),layout_h3(menu_size.width() * 0.12, frame_size.height());QSize layout_v1(menu_size.width(), frame_size.height()*0.8),layout_v2(menu_size.width(), frame_size.height()*0.2);// workspaceui->dock_workspace->setMinimumWidth(layout_h1.width());ui->dock_workspace->setMaximumHeight(frame_size.height());// main view(model and image)ui->tab_mainview->setFixedSize(layout_h2.width() - 10, layout_v1.height());QSize tab_bar_sz = ui->tab_mainview->tabBar()->size();ui->widget_model->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());ui->widght_imgview->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());ui->widget_gl_model->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());// info view(photos and console)QRect view_rt = ui->tab_mainview->frameGeometry();ui->tab_info->setGeometry(view_rt.x(), view_rt.y() + view_rt.height()+5, layout_h2.width() - 10, layout_v2.height());auto tab_sz = ui->tab_info->size();tab_bar_sz = ui->tab_info->tabBar()->size();ui->list_previews->setGeometry(0, 0, tab_sz.width(), tab_sz.height()- tab_bar_sz.height());setMinimumSize(500, 500);}QUpdatePreviewThread::QUpdatePreviewThread(MainWindow *mainwindow)
{mainwindow_ = mainwindow;connect(this, SIGNAL(SingalAddPreview(const QPixmap&, const int&)), this, SLOT(SlotAddPreview(const QPixmap&, const int&)));
}void QUpdatePreviewThread::SlotAddPreview(const QPixmap &pixmap, const int &img_id)
{auto ui = mainwindow_->get_ui();const auto all_images = mainwindow_->get_image_group()->GetAllImages();if(img_id >=all_images.size())return;auto list_preview = ui->list_previews;const QSize icon_sz = list_preview->iconSize();auto image = all_images[img_id];QListWidgetItem* list_item = new QListWidgetItem(QIcon(pixmap),str2qstr(image.get_name()));list_item->setSizeHint(QSize(icon_sz.width(),icon_sz.height()+10));list_preview->insertItem(img_id,list_item);list_preview->repaint();}void QUpdatePreviewThread::run()
{if(mainwindow_ ==nullptr || mainwindow_->get_image_group() ==nullptr){return;}auto ui = mainwindow_->get_ui();const auto new_images = mainwindow_->get_image_group()->GetNewAddingImages();if(new_images.empty()){return;}const auto num_images = new_images.size();QImageReader reader;for(auto k=0;k<num_images;k++){auto image = new_images[k];reader.setFileName(str2qstr(image.get_path()));reader.setAutoTransform(true);const QSize img_size = reader.size();const QSize icon_sz = ui->list_previews->iconSize();const QSize size_scale = img_size.scaled(icon_sz,Qt::KeepAspectRatio);reader.setScaledSize(size_scale);auto pixmap = QPixmap::fromImageReader(&reader);emit SingalAddPreview(pixmap,image.get_id());}}

main.cpp

#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

Qt实战(四)——图片浏览器相关推荐

  1. 用Qt设计一个图片浏览器

    本人分享的是不用ui界面的图片浏览器,它可以从系统文件里面选取各种格式的图片(可以自己设置),然后点击左右的按钮来浏览这些图片,而且还支持图片多选的功能. 以下是Widget.h中的代码: #ifnd ...

  2. Qt之简单图片浏览器

    功能介绍 支持鼠标滚轮放大缩小 支持定时自动播放 支持下一张或下一张图片 说明:功能比较简单(大牛勿喷),就是封装了一层.基本上没有代码的注释,如果大概意思不懂,那么就是笔者写代码的功底不够. 所需知 ...

  3. Qt 仿QQ图片浏览器

    因和项目差异,去除了QQ分享功能和图片切换功能,若需要可自行添加: 图片资源取自网络,未免效果不佳 ,效果图如下: 源码下载链接:http://download.csdn.net/download/u ...

  4. 7.QML Qt Quick——基于Qt Quick Controls 2实现图片浏览器

    Qt Quick Controls 2提供了一组UI控件,例如按钮,标签,复选框,滑块等(用之查之即可).用于在Qt Quick中创建用户界面.UI控件很多,这里通过一个图片浏览器的实现来逐步讲解 图 ...

  5. QT 图片浏览器(一)

    这一段时间在做一个图片浏览器,实现图片左右浏览,图片删除,图片旋转的功能,在初期的时候我在window系统下面的QT Creator中编写代码,编写以后实现了以上所说的功能.虽然难度不是很大,但是在编 ...

  6. Qt实践3: 图片浏览器

    Qt实现图片浏览器 Qt实践3: 图片浏览器 引言 因课程教学,需要利用Qt做图形界面设计(GUI).自学Qt两月有余,发现现有很多资料,讲述C++程序设计QT项目的较多,不利于新手入门,特别是对于C ...

  7. 23.Qt Quick QML-400行实现一个好看的图片浏览器-支持多个图片浏览、缩放、旋转、滑轮切换图片...

    之前我们已经学习了Image.Layout布局.MouseArea.Button.GroupBox.FileDialog等控件. 所以本章综合之前的每章的知识点,来做一个图片浏览器,笔者使用的Qt版本 ...

  8. iOS开发系列--无限循环的图片浏览器

    概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授 ...

  9. ImageView组件的应用:图片浏览器

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) 本实例用来练习ImageView组件的使用,实现一个图片浏览器,该图片浏览器可以改变所查看的图片的透明度,切换 ...

最新文章

  1. zigbee 协议栈的时钟和定时器分频
  2. Ubuntu16.04 php7.0+mysql5.7+apache2环境搭配
  3. JavaScript-正则表达式
  4. android ndk gcc,Android NDK GCC似乎是铿锵的 - 它应该是这样吗?
  5. 交换机指定外部DHCP服务器,H3C交换机DHCP服务器设置步骤
  6. 自适应好看的引导单页源码-无后台
  7. java map 实例_java中map集合嵌套形式简单示例
  8. java 分级显示_上级部门与下级部门的分类显示
  9. 运行CATIA2018主程序setup.exe时,报错setup:Problem with VC11 Runtime installation
  10. C语言小项目——电子秒表(毫秒级)
  11. RouterOS 端口映射
  12. 11个LOGO设计灵感网站推荐,帮你提高LOGO设计工作效率
  13. 澳洲2022人口普查结果出炉--华人占比开始下降
  14. 《中国近代史纲要》考试过关?Python帮你划重点
  15. 史上最全的全国特产一览表,到哪就买当地最正宗的特产!!!
  16. ubuntu下向163发送邮件
  17. 抖音算法推荐机制详解
  18. mt6761平台 源码内置APK报错“/lib/xxxx.so“ not found
  19. 大神崛起必备的10大练手的Python项目 墙裂建议收藏!
  20. 数据透视表(2)|计算字段、计算项

热门文章

  1. 手机背光检测设备,三菱5U程序案例
  2. 最新QT下载和安装 指南教程
  3. ps基础入门知识课程教程学习文字设计制作小白
  4. 触控科技陈昊芝:捕鱼达人装机量1亿 月活跃用户3246万
  5. 国产蓝牙耳机哪个牌子好?口碑最好的国产蓝牙耳机推荐
  6. 微信小程序自动化测试的研究过程
  7. 计算机网络读后感500字,骆驼祥子读后感500字
  8. 淮阴工学院计算机科学与技术咋样,淮阴工学院计算机学院计算机科学与技术专业(NIIT)人才培养方案介绍...
  9. Skynet搭建的棋牌服务器实现部分Lua业务热更新
  10. 营业执照扫描识别OCR的技术用处不大,大家还是不要关注了