qt使用笔记三之 QGraphicsView、QGraphicsScene 和 QGraphicsPixmapItem 详解
qt使用笔记三之 QGraphicsView、QGraphicsScene 和 QGraphicsPixmapItem 详解
-
Qt的Graphics View框架提供了一个强大的平台,用于管理和交互大量的自定义2D图形项。这三个核心类构成了该框架的基础:
-
QGraphicsScene:作为图形项的容器,管理所有图形项
-
QGraphicsView:作为可视化窗口,用于显示场景内容
-
QGraphicsPixmapItem:用于显示图像的专用图形项
-
1. QGraphicsScene(图形场景)
- QGraphicsScene 是 Qt Graphics View 框架中的场景类,它充当所有图形项的容器。场景定义了项目的坐标空间,并负责管理大量图形项的状态,如选择、焦点和悬停等。
主要特性:- 管理大量图形项的高效容器- 传播事件到各个图形项- 提供无变换的场景坐标系统- 管理图形项的选择、聚焦和悬停状态- 提供场景渲染的基类
- 常用方法:
// 添加和移除图形项
QGraphicsItem* addItem(QGraphicsItem *item);
void removeItem(QGraphicsItem *item);// 查找图形项
QList<QGraphicsItem*> items() const;
QList<QGraphicsItem*> items(Qt::SortOrder order = Qt::DescendingOrder) const;// 场景边界管理
void setSceneRect(const QRectF &rect);
QRectF sceneRect() const;// 渲染
void render(QPainter *painter, const QRectF &target = QRectF(), const QRectF &source = QRectF(), Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);// 事件处理
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
2. QGraphicsView(图形视图)
- QGraphicsView 是用于可视化 QGraphicsScene 内容的窗口部件。它提供了滚动条、变换(缩放和旋转)以及将场景渲染到不同绘图设备的能力。
主要特性:提供滚动条以便浏览大场景支持变换(缩放和旋转)可以将场景渲染到不同的绘图设备支持多种渲染后端(OpenGL、普通绘图等)提供多种交互模式
- 常用方法:
// 场景管理
void setScene(QGraphicsScene *scene);
QGraphicsScene* scene() const;// 视图变换
void scale(qreal sx, qreal sy);
void rotate(qreal angle);
void translate(qreal dx, qreal dy);
void resetTransform();// 视图模式设置
void setDragMode(DragMode mode); // ScrollHandDrag, RubberBandDrag等// 坐标转换
QPointF mapToScene(const QPoint &point) const;
QPoint mapFromScene(const QPointF &point) const;// 渲染控制
void setRenderHint(QPainter::RenderHint hint, bool on = true);
void setViewportUpdateMode(ViewportUpdateMode mode);
3. QGraphicsPixmapItem(位图图形项)
- QGraphicsPixmapItem 是 QGraphicsItem 的子类,专门用于显示 QPixmap 图像。它提供了图像显示、变换和交互的基本功能。
主要特性:在图形场景中专用于显示QPixmap图像实现透明度 和 图像的变换(缩放、旋转等)作为复杂图形场景的背景或元素可以设置偏移量和变换原点
- 常用方法:
// 图像管理
void setPixmap(const QPixmap &pixmap);
QPixmap pixmap() const;// 偏移量设置
void setOffset(const QPointF &offset);
void setOffset(qreal x, qreal y);
QPointF offset() const;// 变换模式
void setTransformationMode(Qt::TransformationMode mode);
Qt::TransformationMode transformationMode() const;// 图形项属性
virtual QRectF boundingRect() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr);
三者的关系
QGraphicsView (视图/窗口)|| 显示|
QGraphicsScene (场景/容器)|| 包含|
QGraphicsPixmapItem (图形项/图像)
- 一个场景可以有多个视图
- 一个场景可以包含多个图形项
- 视图负责将场景内容呈现给用户
4. 封装好的 图像显示类
- imageviewer.h
#ifndef IMAGEVIEWER_H
#define IMAGEVIEWER_H#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QPointF>class ImageViewer : public QGraphicsView
{Q_OBJECTpublic:explicit ImageViewer(QWidget* parent = nullptr);// 图像操作bool loadImage(const QString& fileName);void setImage(QImage& qimage);void clearImage();// 视图操作void zoomIn();void zoomOut();void resetView();void fitToWindow();// 获取当前状态bool hasImage() const;double scaleFactor() const;signals:// 坐标变化信号void mousePositionChanged(const QPointF& scenePos);protected:// 事件处理void wheelEvent(QWheelEvent* event) override;void mousePressEvent(QMouseEvent* event) override;void mouseMoveEvent(QMouseEvent* event) override;void mouseReleaseEvent(QMouseEvent* event) override;private:// 初始化设置void setupView();// 缩放控制void scaleView(double factor);// 成员变量QGraphicsScene* scene;QGraphicsPixmapItem* pixmapItem;double currentScale;bool isDragging;QPoint lastDragPos;
};#endif // IMAGEVIEWER_H
- imageviewer.cpp
#include "imageviewer.h"
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QFileDialog>
#include <QMessageBox>
#include <QScrollBar>
#include <QtMath>ImageViewer::ImageViewer(QWidget* parent): QGraphicsView(parent), scene(nullptr), pixmapItem(nullptr),currentScale(1.0), isDragging(false)
{// 创建场景scene = new QGraphicsScene(this);setScene(scene);// 设置视图属性setupView();
}void ImageViewer::setupView()
{// 设置渲染提示setRenderHint(QPainter::Antialiasing, true);setRenderHint(QPainter::SmoothPixmapTransform, true);setRenderHint(QPainter::TextAntialiasing, true);// 设置视图属性setDragMode(QGraphicsView::ScrollHandDrag);setTransformationAnchor(QGraphicsView::AnchorUnderMouse);setResizeAnchor(QGraphicsView::AnchorUnderMouse);setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);setFrameShape(QFrame::NoFrame);// 设置背景setBackgroundBrush(QBrush(QColor(50, 50, 50)));
}bool ImageViewer::loadImage(const QString& fileName)
{// 加载图像QPixmap pixmap(fileName);if (pixmap.isNull()) {return false;}// 清除现有内容clearImage();// 创建新的图像项pixmapItem = scene->addPixmap(pixmap);scene->setSceneRect(pixmap.rect());// 重置视图resetView();return true;
}void ImageViewer::setImage(QImage& qimage)
{// 清除现有内容clearImage();QPixmap pixmap = QPixmap::fromImage(qimage);// 创建新的图像项pixmapItem = scene->addPixmap(pixmap);scene->setSceneRect(pixmap.rect());// 重置视图resetView();
}void ImageViewer::clearImage()
{// 清除场景scene->clear();pixmapItem = nullptr;currentScale = 1.0;
}void ImageViewer::zoomIn()
{scaleView(1.2);
}void ImageViewer::zoomOut()
{scaleView(1.0 / 1.2);
}void ImageViewer::resetView()
{// 重置变换//resetTransform();fitToWindow();currentScale = 1.0;// 如果存在图像,居中显示if (pixmapItem) {centerOn(pixmapItem);}
}void ImageViewer::fitToWindow()
{if (pixmapItem) {// 适应窗口大小fitInView(scene->sceneRect(), Qt::KeepAspectRatio);// 更新当前缩放比例QTransform transform = this->transform();currentScale = transform.m11();}
}bool ImageViewer::hasImage() const
{return pixmapItem != nullptr;
}double ImageViewer::scaleFactor() const
{return currentScale;
}void ImageViewer::scaleView(double factor)
{// 应用缩放scale(factor, factor);currentScale *= factor;
}void ImageViewer::wheelEvent(QWheelEvent* event)
{if (pixmapItem) {// 计算缩放因子double factor = qPow(1.2, event->angleDelta().y() / 240.0);scaleView(factor);event->accept();}else {QGraphicsView::wheelEvent(event);}
}void ImageViewer::mousePressEvent(QMouseEvent* event)
{if (event->button() == Qt::LeftButton && pixmapItem) {// 开始拖拽setCursor(Qt::ClosedHandCursor);lastDragPos = event->pos();isDragging = true;event->accept();}else {QGraphicsView::mousePressEvent(event);}
}void ImageViewer::mouseMoveEvent(QMouseEvent* event)
{if (pixmapItem) {// 获取场景坐标QPointF scenePos = mapToScene(event->pos());// 发射坐标变化信号emit mousePositionChanged(scenePos);// 处理拖拽if (isDragging && (event->buttons() & Qt::LeftButton)) {// 计算移动距离QPoint delta = event->pos() - lastDragPos;lastDragPos = event->pos();// 移动滚动条horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x());verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y());event->accept();}else {QGraphicsView::mouseMoveEvent(event);}}else {QGraphicsView::mouseMoveEvent(event);}
}void ImageViewer::mouseReleaseEvent(QMouseEvent* event)
{if (event->button() == Qt::LeftButton && isDragging) {// 结束拖拽setCursor(Qt::ArrowCursor);isDragging = false;event->accept();}else {QGraphicsView::mouseReleaseEvent(event);}
}