图片浏览器逻辑
实现图片浏览器用到了前面几乎所有的知识,包括窗口部件、布局、事件、对象模型与容器类、图形视图、模型/视图编程以及多线程等。大致流程为:首先定义一个图片类,该类包含图片的路径、文件名、文件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);
- }
-
- //设置相机所属的id
- void 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_;
- }
-
- //获取相机id
- const 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_OBJECT
-
- public:
- 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_OBJECT
-
- public:
- 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);
-
- //初始化Ui
- InitDockView();
- 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 view
- auto 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 view
- auto 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()
- {
- //初始化dockView
- auto 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);
-
- //通过线程来创建previews
- QUpdatePreviewThread* 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 view
- updateTreeView();
- //更新preview view
- updatePreView();
-
- }
-
- 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());
-
- //repaint
- auto 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);
-
- // workspace
- ui->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实战之实现图片浏览器的详细内容,更多关于Qt图片浏览器的资料请关注w3xue其它相关文章!