经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » HTML/CSS » 浏览器 » 查看文章
Qt实战之实现图片浏览器
来源:jb51  时间:2023/3/17 8:57:49  对本文有异议

图片浏览器逻辑

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

效果图

具体实现

utils.h

  1. #ifndef UTILS_H
  2. #define UTILS_H
  3. #include<QString>
  4. #include<string>
  5. //string to QString
  6. inline QString str2qstr(const std::string& str)
  7. {
  8. return QString::fromLocal8Bit(str.data());
  9. }
  10. //QString to string
  11. inline std::string qstr2str(const QString& qstr)
  12. {
  13. QByteArray cdata = qstr.toLocal8Bit();
  14. return std::string(cdata);
  15. }
  16. #endif // UTILS_H

image.h

  1. #ifndef IMAGE_H
  2. #define IMAGE_H
  3. #include<string>
  4. #include<vector>
  5. using std::vector;
  6. using std::string;
  7. class Image
  8. {
  9. public:
  10. Image() = default;
  11. ~Image() = default;
  12. Image(const string& _path,const unsigned& _id):path_(_path),id_(_id){
  13. //从路径中获取图像名称
  14. auto pos = path_.find_last_of('\\') +1;
  15. if(pos == 0)
  16. {
  17. pos = path_.find_last_of('/')+1;
  18. }
  19. name_ = path_.substr(pos,path_.length() - pos);
  20. pos = name_.find_last_of('.');
  21. name_ = name_.substr(0,pos);
  22. }
  23. //设置相机所属的id
  24. void set_cam_id(const unsigned& _id){
  25. cam_id_ = _id;
  26. }
  27. //获取路径
  28. const string& get_path(){
  29. return path_;
  30. }
  31. //获取文件名
  32. const string& get_name(){
  33. return name_;
  34. }
  35. const unsigned &get_id(){
  36. return id_;
  37. }
  38. //获取相机id
  39. const unsigned& get_cam_id(){
  40. return cam_id_;
  41. }
  42. private:
  43. string path_;
  44. string name_;
  45. unsigned id_;
  46. unsigned cam_id_;
  47. };
  48. #endif // IMAGE_H

image_group.h

  1. #ifndef IMAGE_GROUP_H
  2. #define IMAGE_GROUP_H
  3. #include"image.h"
  4. class image_group
  5. {
  6. public:
  7. image_group();
  8. ~image_group();
  9. public:
  10. bool addImages(const vector<string>& img_paths);
  11. const vector<Image>& GetAllImages();
  12. const vector<Image>& GetNewAddingImages();
  13. private:
  14. //所有图片数组
  15. vector<Image> all_images_;
  16. //新加入的图片数组
  17. vector<Image> new_images_;
  18. };
  19. #endif // IMAGE_GROUP_H

image_group.cpp

  1. #include "image_group.h"
  2. image_group::image_group()
  3. {
  4. }
  5. image_group::~image_group()
  6. {
  7. }
  8. bool image_group::addImages(const vector<std::string> &img_paths)
  9. {
  10. new_images_.clear();
  11. for(auto& path: img_paths)
  12. {
  13. all_images_.emplace_back(path,all_images_.size());
  14. new_images_.emplace_back(path,all_images_.size());
  15. }
  16. return true;
  17. }
  18. const vector<Image> &image_group::GetAllImages()
  19. {
  20. return all_images_;
  21. }
  22. const vector<Image> &image_group::GetNewAddingImages()
  23. {
  24. return new_images_;
  25. }

qimgviewwidget.h

  1. #ifndef QIMGVIEWWIDGET_H
  2. #define QIMGVIEWWIDGET_H
  3. #include <QWidget>
  4. #include<QImage>
  5. //用于显示2D图像的窗口部件
  6. class QImgViewWidget : public QWidget
  7. {
  8. Q_OBJECT
  9. public:
  10. explicit QImgViewWidget(QWidget *parent = nullptr);
  11. ~QImgViewWidget() = default;
  12. //从文件路径加载图片
  13. void SetImage(const QString& img_path);
  14. void ResetTransform();
  15. private:
  16. //用来展示的image信息
  17. QImage img_display_;
  18. //原始pixmap信息
  19. QPixmap pix_ori_;
  20. //用来展示的pixmap信息
  21. QPixmap pix_display_;
  22. //图片路径
  23. QString img_path_;
  24. //鼠标滚轮控制的缩放比例
  25. float zoom_scale_;
  26. //由鼠标移动控制的移动
  27. QPoint move_step_;
  28. bool move_start_;
  29. bool is_moving_;
  30. QPoint mouse_point_;
  31. protected:
  32. void paintEvent(QPaintEvent* event)override;
  33. void wheelEvent(QWheelEvent* event)override;
  34. void mousePressEvent(QMouseEvent* event)override;
  35. void mouseReleaseEvent(QMouseEvent* event)override;
  36. void mouseMoveEvent(QMouseEvent* event)override;
  37. void resizeEvent(QResizeEvent* event)override;
  38. };
  39. #endif // QIMGVIEWWIDGET_H

qimgviewwidget.cpp

  1. #include "qimgviewwidget.h"
  2. #include <QPainter>
  3. #include <QWheelEvent>
  4. QImgViewWidget::QImgViewWidget(QWidget *parent) : QWidget(parent)
  5. {
  6. zoom_scale_ = 1.0f;
  7. move_start_ = false;
  8. is_moving_ = false;
  9. }
  10. void QImgViewWidget::SetImage(const QString &img_path)
  11. {
  12. ResetTransform();
  13. QSize view_size = size();
  14. //通过QImage加载图像
  15. img_path_ = img_path;
  16. img_display_.load(img_path_);
  17. pix_ori_ = QPixmap::fromImage(img_display_);
  18. pix_display_ = pix_ori_.scaled(zoom_scale_ *size(),Qt::KeepAspectRatio);
  19. }
  20. void QImgViewWidget::ResetTransform()
  21. {
  22. //重新设置缩放比例和移动位置
  23. zoom_scale_ = 1.0f;
  24. move_step_ = QPoint(0,0);
  25. }
  26. void QImgViewWidget::paintEvent(QPaintEvent *event)
  27. {
  28. QPainter painter(this);
  29. painter.drawPixmap(move_step_.x()+(width()-pix_display_.width())/2,move_step_.y()+(height()- pix_display_.height()) / 2,pix_display_);
  30. }
  31. void QImgViewWidget::wheelEvent(QWheelEvent *event)
  32. {
  33. //随滚轮缩放
  34. if(event->delta()>0)
  35. {
  36. zoom_scale_ *= 1.1;
  37. }
  38. else {
  39. zoom_scale_ *=0.9;
  40. }
  41. pix_display_ = pix_ori_.scaled(zoom_scale_ * size(),Qt::KeepAspectRatio);
  42. update();
  43. }
  44. void QImgViewWidget::mousePressEvent(QMouseEvent *event)
  45. {
  46. if(event->button() == Qt::LeftButton)
  47. {
  48. if(!move_start_)
  49. {
  50. move_start_ = true;
  51. is_moving_ = false;
  52. mouse_point_ = event->globalPos();
  53. }
  54. }
  55. }
  56. void QImgViewWidget::mouseReleaseEvent(QMouseEvent *event)
  57. {
  58. if(event->button() ==Qt::LeftButton)
  59. {
  60. if(move_start_)
  61. {
  62. move_start_ = false;
  63. is_moving_ = false;
  64. }
  65. }
  66. }
  67. void QImgViewWidget::mouseMoveEvent(QMouseEvent *event)
  68. {
  69. if(move_start_)
  70. {
  71. const QPoint mos_pt = event->globalPos();
  72. move_step_ +=mos_pt - mouse_point_;
  73. is_moving_ = true;
  74. mouse_point_ = mos_pt;
  75. repaint();
  76. }
  77. }
  78. void QImgViewWidget::resizeEvent(QResizeEvent *event)
  79. {
  80. pix_display_ = pix_ori_.scaled(zoom_scale_ *size(),Qt::KeepAspectRatio);
  81. update();
  82. }

mainwindow.h

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include"image_group.h"
  5. #include<QThread>
  6. namespace Ui {
  7. class MainWindow;
  8. }
  9. class MainWindow : public QMainWindow
  10. {
  11. Q_OBJECT
  12. public:
  13. MainWindow(QWidget *parent = Q_NULLPTR);
  14. // ~MainWindow();
  15. image_group* get_image_group(){
  16. return &image_group_;
  17. }
  18. Ui::MainWindow* get_ui(){
  19. return ui;
  20. }
  21. void InitTreeView();
  22. void InitPrewView();
  23. void InitDockView();
  24. void InitTabView();
  25. void InitLayout();
  26. void updateTreeView();
  27. void updatePreView();
  28. private slots:
  29. void OnActionAddImages();
  30. void OnActiondoubleClickedTreeImage(const QModelIndex& index);
  31. protected:
  32. void paintEvent(QPaintEvent* event)override;
  33. void resizeEvent(QResizeEvent* event)override;
  34. private:
  35. Ui::MainWindow *ui;
  36. image_group image_group_;
  37. };
  38. class QUpdatePreviewThread :public QThread
  39. {
  40. Q_OBJECT
  41. public:
  42. QUpdatePreviewThread(MainWindow* mainwindow);
  43. signals:
  44. void SingalAddPreview(const QPixmap& pixmap,const int& img_id);
  45. private slots:
  46. void SlotAddPreview(const QPixmap& pixmap,const int& img_id);
  47. protected:
  48. void run() override;
  49. private:
  50. MainWindow* mainwindow_;
  51. };
  52. #endif // MAINWINDOW_H

mainwindow.cpp

  1. #include"utils.h"
  2. #include "mainwindow.h"
  3. #include "ui_mainwindow.h"
  4. #include<QStandardItemModel>
  5. #include<QFileDialog>
  6. #include<QMessageBox>
  7. #include<QResizeEvent>
  8. #include<QListWidgetItem>
  9. #include<QImageReader>
  10. MainWindow::MainWindow(QWidget *parent) :
  11. QMainWindow(parent),
  12. ui(new Ui::MainWindow)
  13. {
  14. ui->setupUi(this);
  15. setWindowState(Qt::WindowMaximized);
  16. //初始化Ui
  17. InitDockView();
  18. InitTreeView();
  19. InitTabView();
  20. InitPrewView();
  21. InitLayout();
  22. connect(ui->action_addimages,&QAction::triggered,this,&MainWindow::OnActionAddImages);
  23. connect(ui->tree_images,&QTreeView::doubleClicked,this,&MainWindow::OnActiondoubleClickedTreeImage);
  24. connect(ui->list_previews,&QTreeView::doubleClicked,this,&MainWindow::OnActiondoubleClickedTreeImage);
  25. }
  26. void MainWindow::InitTreeView()
  27. {
  28. //初始化tree view
  29. auto tree_imgs = ui->tree_images;
  30. auto* model = new QStandardItemModel(tree_imgs);
  31. tree_imgs->setModel(model);
  32. model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("images"));
  33. tree_imgs->setEditTriggers(QAbstractItemView::NoEditTriggers);
  34. }
  35. void MainWindow::InitPrewView()
  36. {
  37. //初始化preview view
  38. auto list_preview = ui->list_previews;
  39. list_preview->setIconSize(QSize(100,100));
  40. list_preview->setResizeMode(QListView::Adjust);
  41. list_preview->setViewMode(QListView::IconMode);
  42. list_preview->setMovement(QListView::Static);
  43. list_preview->setSpacing(10);
  44. }
  45. void MainWindow::InitDockView()
  46. {
  47. //初始化dockView
  48. auto dp_workspace = (QDockWidget*)ui->dock_workspace;
  49. dp_workspace->setWindowTitle("Wokspace");
  50. addDockWidget(Qt::LeftDockWidgetArea,dp_workspace);
  51. }
  52. void MainWindow::InitTabView()
  53. {
  54. //2d/3d部件的样式表
  55. // auto tab_view = ui->tab_mainview;
  56. // 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;}// ");
  57. // tab_view->setCurrentIndex(0);
  58. // auto wid_model = ui->widget_model;
  59. // wid_model->setStyleSheet("background-color:rgb(80,80,80);");
  60. // auto wid_image = ui->widght_imgview;
  61. // wid_image->setStyleSheet(" background-color:rgb(80,80,80);");
  62. // //照片/控制台部件样式表
  63. // auto tab_info = ui->tab_info;
  64. // 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;}// ");
  65. // auto wid_priviews = ui->widget_previews;
  66. // wid_priviews->setStyleSheet(" background-color:rgb(80,80,80);");
  67. // auto wid_console = ui->widget_console;
  68. // wid_console->setStyleSheet(" background-color:rgb(80,80,80);");
  69. }
  70. void MainWindow::InitLayout()
  71. {
  72. }
  73. void MainWindow::updateTreeView()
  74. {
  75. //相关操作后更新tree view。例如,加载图像
  76. const auto all_images = image_group_.GetAllImages();
  77. const auto new_images = image_group_.GetNewAddingImages();
  78. if(new_images.empty())
  79. return;
  80. const auto num_allimages = all_images.size();
  81. const auto num_images = new_images.size();
  82. auto* tree = ui->tree_images;
  83. auto* model = static_cast<QStandardItemModel*>(tree->model());
  84. QString str_title = QString("All Images (%1 Images)").arg(num_allimages);
  85. if(model->item(0,0) ==nullptr)
  86. {
  87. model->setItem(0,0,new QStandardItem(str_title));
  88. }
  89. else {
  90. auto item = model->item(0,0);
  91. item->setText(str_title);
  92. }
  93. //为tree添加图片的名字
  94. for(auto image:new_images)
  95. {
  96. model->item(0,0)->setChild(image.get_id(),0,new QStandardItem(str2qstr(image.get_name())));
  97. }
  98. tree->setExpanded(model->index(0,0),true);
  99. auto workspace = static_cast<QDockWidget*>(ui->dock_workspace);
  100. auto ws_size = workspace->frameSize();
  101. tree->setFixedWidth(ws_size.width());
  102. }
  103. void MainWindow::updatePreView()
  104. {
  105. auto tab_info = ui->tab_info;
  106. tab_info->setCurrentIndex(0);
  107. //通过线程来创建previews
  108. QUpdatePreviewThread* thread = new QUpdatePreviewThread(this);
  109. thread->start();
  110. }
  111. void MainWindow::OnActionAddImages()
  112. {
  113. QStringList file_paths = QFileDialog::getOpenFileNames(this,tr("Image Path"),"Data\\", tr("Image Files(*png *jpg *tif);"));
  114. //添加图片
  115. vector<string> str_paths;
  116. for(auto path:file_paths)
  117. {
  118. str_paths.push_back(qstr2str(path));
  119. }
  120. image_group_.addImages(str_paths);
  121. //更新tree view
  122. updateTreeView();
  123. //更新preview view
  124. updatePreView();
  125. }
  126. void MainWindow::OnActiondoubleClickedTreeImage(const QModelIndex &index)
  127. {
  128. QMessageBox msg_box;
  129. auto* tree = ui->tree_images;
  130. auto* model = static_cast<QStandardItemModel*>(tree->model());
  131. unsigned img_id = index.row();
  132. const auto all_images = image_group_.GetAllImages();
  133. if(img_id>=all_images.size())
  134. {
  135. msg_box.setText("data error");
  136. msg_box.exec();
  137. return;
  138. }
  139. //获得双击的图片路径
  140. auto image = all_images[img_id];
  141. auto imgpath = str2qstr(image.get_path());
  142. //repaint
  143. auto img_view = ui->widght_imgview;
  144. img_view->SetImage(imgpath);
  145. img_view->repaint();
  146. }
  147. void MainWindow::paintEvent(QPaintEvent* event)
  148. {
  149. }
  150. void MainWindow::resizeEvent(QResizeEvent* event)
  151. {
  152. //自动调整所有小部件的大小
  153. const QSize size = event->size();
  154. const QRect frame_geometry = ui->central_widget->geometry();
  155. const QSize frame_size = ui->central_widget->size();
  156. const QSize menu_size = ui->menuBar->size();
  157. QSize layout_h1(menu_size.width() * 0.12, frame_size.height()),
  158. layout_h2(menu_size.width() * 0.76, frame_size.height()),
  159. layout_h3(menu_size.width() * 0.12, frame_size.height());
  160. QSize layout_v1(menu_size.width(), frame_size.height()*0.8),
  161. layout_v2(menu_size.width(), frame_size.height()*0.2);
  162. // workspace
  163. ui->dock_workspace->setMinimumWidth(layout_h1.width());
  164. ui->dock_workspace->setMaximumHeight(frame_size.height());
  165. // main view(model and image)
  166. ui->tab_mainview->setFixedSize(layout_h2.width() - 10, layout_v1.height());
  167. QSize tab_bar_sz = ui->tab_mainview->tabBar()->size();
  168. ui->widget_model->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());
  169. ui->widght_imgview->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());
  170. ui->widget_gl_model->setFixedSize(layout_h2.width() - 10, layout_v1.height() - tab_bar_sz.height());
  171. // info view(photos and console)
  172. QRect view_rt = ui->tab_mainview->frameGeometry();
  173. ui->tab_info->setGeometry(view_rt.x(), view_rt.y() + view_rt.height()+5, layout_h2.width() - 10, layout_v2.height());
  174. auto tab_sz = ui->tab_info->size();
  175. tab_bar_sz = ui->tab_info->tabBar()->size();
  176. ui->list_previews->setGeometry(0, 0, tab_sz.width(), tab_sz.height()- tab_bar_sz.height());
  177. setMinimumSize(500, 500);
  178. }
  179. QUpdatePreviewThread::QUpdatePreviewThread(MainWindow *mainwindow)
  180. {
  181. mainwindow_ = mainwindow;
  182. connect(this, SIGNAL(SingalAddPreview(const QPixmap&, const int&)), this, SLOT(SlotAddPreview(const QPixmap&, const int&)));
  183. }
  184. void QUpdatePreviewThread::SlotAddPreview(const QPixmap &pixmap, const int &img_id)
  185. {
  186. auto ui = mainwindow_->get_ui();
  187. const auto all_images = mainwindow_->get_image_group()->GetAllImages();
  188. if(img_id >=all_images.size())
  189. return;
  190. auto list_preview = ui->list_previews;
  191. const QSize icon_sz = list_preview->iconSize();
  192. auto image = all_images[img_id];
  193. QListWidgetItem* list_item = new QListWidgetItem(QIcon(pixmap),str2qstr(image.get_name()));
  194. list_item->setSizeHint(QSize(icon_sz.width(),icon_sz.height()+10));
  195. list_preview->insertItem(img_id,list_item);
  196. list_preview->repaint();
  197. }
  198. void QUpdatePreviewThread::run()
  199. {
  200. if(mainwindow_ ==nullptr || mainwindow_->get_image_group() ==nullptr)
  201. {
  202. return;
  203. }
  204. auto ui = mainwindow_->get_ui();
  205. const auto new_images = mainwindow_->get_image_group()->GetNewAddingImages();
  206. if(new_images.empty())
  207. {
  208. return;
  209. }
  210. const auto num_images = new_images.size();
  211. QImageReader reader;
  212. for(auto k=0;k<num_images;k++)
  213. {
  214. auto image = new_images[k];
  215. reader.setFileName(str2qstr(image.get_path()));
  216. reader.setAutoTransform(true);
  217. const QSize img_size = reader.size();
  218. const QSize icon_sz = ui->list_previews->iconSize();
  219. const QSize size_scale = img_size.scaled(icon_sz,Qt::KeepAspectRatio);
  220. reader.setScaledSize(size_scale);
  221. auto pixmap = QPixmap::fromImageReader(&reader);
  222. emit SingalAddPreview(pixmap,image.get_id());
  223. }
  224. }

main.cpp

  1. #include "mainwindow.h"
  2. #include <QApplication>
  3. int main(int argc, char *argv[])
  4. {
  5. QApplication a(argc, argv);
  6. MainWindow w;
  7. w.show();
  8. return a.exec();
  9. }

以上就是Qt实战之实现图片浏览器的详细内容,更多关于Qt图片浏览器的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号