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_OBJECT
public:
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);
}
}