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_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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值