Qt开发之图形视图

一、GraphicsView框架结构

Qt的GraphicsView框架是一个用于2D图形渲染和交互的框架,它为开发者提供了一种灵活的方式来创建自定义的图形界面和场景。以下是Qt GraphicsView框架的主要组件和结构分析:

  1. 场景(Scene):QGraphicsSceneGraphicsView的核心概念之一。场景充当图形项(Item)的容器,它负责管理图形项的添加、移动、删除以及事件分发。场景可以是一个虚拟的2D绘图区域,你可以在其中添加各种图形项。

  2. 图形项(Item):图形项是场景中的可视元素,可以是图形、文本、图像等。QGraphicsItem 是图形项的基类,你可以从它派生自定义的图形项。图形项可以在场景中放置、移动和变换,它们可以响应用户交互和事件。

  3. 视图(View):QGraphicsView 是图形场景的可视化表示,它负责将场景中的图形项渲染到屏幕上。视图可以进行缩放、平移、旋转等操作,以便用户查看和交互场景中的图形项。

  4. 图形引擎(Graphics Engine):Qt的GraphicsView框架使用了图形引擎来进行渲染。这允许你在不同平台上以高性能方式呈现图形。通常情况下,Qt使用了底层的OpenGL或者软件渲染引擎,具体取决于平台和配置。

  5. 视图框架(View Framework):GraphicsView提供了视图框架,允许你创建多个视图以查看同一个场景,或者在多个场景之间切换。这对于复杂的图形界面或需要多个视图的应用程序非常有用。

  6. 事件处理(Event Handling):GraphicsView框架允许图形项响应用户事件,例如鼠标点击、拖拽、键盘输入等。你可以重写图形项的事件处理函数以实现自定义的交互逻辑。

  7. 图形项组合(Item Composition):图形项可以嵌套在组合项中,以形成更复杂的结构。这允许你创建复杂的图形元素,例如符号、图标或者自定义图形。

  8. 坐标转换(Coordinate Transformations):GraphicsView框架提供了用于坐标转换的功能,这允许你将图形项坐标从场景坐标系转换为视图坐标系,以便正确呈现图形。

  9. 选择和焦点(Selection and Focus):GraphicsView框架支持图形项的选择和焦点处理。用户可以选择图形项并将焦点设置到它们上,这对于编辑应用程序非常有用。

  10. 动画(Animation):你可以使用Qt的动画框架与GraphicsView结合,实现动画效果来移动、旋转、缩放图形项。

总之,Qt的GraphicsView框架提供了一个强大的工具,用于创建自定义的2D图形界面和图形应用程序。它使得开发者能够方便地创建交互式的图形应用程序,支持丰富的图形元素、事件处理和视图操作。

二、场景QGraphicsScene类

QGraphicsScene 是 Qt 中 GraphicsView 框架的一个核心类,用于管理2D图形项(QGraphicsItem)的容器,充当图形场景的背景。它提供了一种用于创建、排列、渲染和交互图形项的机制。下面是关于 QGraphicsScene 类的一些重要信息:

场景的创建:你可以通过创建一个 QGraphicsScene 的实例来初始化一个场景。通常,你可以在应用程序的主窗口或一个视图中创建场景。

QGraphicsScene *scene = new QGraphicsScene;

添加和删除图形项:使用场景的 addItem 函数可以将图形项添加到场景中,使用 removeItem 函数可以从场景中删除图形项。

QGraphicsItem *item = new QGraphicsItem;
scene->addItem(item);

场景尺寸:场景可以具有自定义的尺寸,可以使用 setSceneRect 函数设置场景的矩形区域。

scene->setSceneRect(0, 0, 800, 600);

场景视图关联:场景通常与一个或多个视图(QGraphicsView)相关联,视图用于在屏幕上呈现场景中的图形项。你可以在视图中显示同一个场景,也可以创建多个场景和视图的组合。

QGraphicsView *view = new QGraphicsView(scene);

事件处理:场景可以处理和分发鼠标事件、键盘事件和其他事件给场景中的图形项。你可以重写场景的事件处理函数来处理这些事件。
选择和焦点:场景支持图形项的选择和焦点,用户可以选择图形项并设置焦点。你可以使用 setSelectionArea 和 clearSelection 来控制选择,使用 setFocusItem 来设置焦点图形项。
场景的渲染:场景可以呈现自己的图形项,也可以与视图协同工作来渲染图形。它支持对图形项的渲染和更新。
信号和槽:场景可以发出信号以响应图形项的更改,你可以使用信号和槽机制来捕捉这些事件并执行相应的操作。

使用示例:

#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QGraphicsScene scene;
    QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
    scene.addItem(rectItem);

    QGraphicsView view(&scene);
    view.show();

    return app.exec();
}

三、图形项QGraphicsItem类

QGraphicsItem 类是 Qt 中 GraphicsView 框架的核心类之一,用于表示2D图形场景中的图形项。它提供了一个抽象基类,可以通过继承它来创建自定义的图形项,以便在场景中渲染、排列和与用户进行交互。

QGraphicsItem 类的主要特性和功能:

  1. 绘制和渲染:你可以重写 QGraphicsItem 类的 paint() 函数来自定义图形项的绘制。在这个函数中,你可以使用 QPainter 对象进行绘制操作。你可以绘制图形、文本、图像等。

  2. 坐标系:每个 QGraphicsItem 都有自己的局部坐标系,允许你在图形项内部定义和绘制图形。你可以使用 pos()setPos() 函数来获取和设置图形项的位置。

  3. 变换和变换矩阵:你可以使用变换矩阵(QTransform)来对图形项进行旋转、缩放、平移和其他变换操作。使用 setTransform() 函数来设置变换。

  4. 外观:每个图形项可以有自定义的外观属性,如画笔(QPen)和刷子(QBrush),用于指定图形项的绘制样式。

  5. 事件处理:QGraphicsItem 具有一系列虚拟函数,用于处理鼠标事件、键盘事件、焦点事件等。你可以重写这些函数来实现自定义的交互逻辑,例如捕捉鼠标点击事件或键盘按键事件。

  6. 碰撞检测:QGraphicsItem 提供了 collidesWithItem()collidesWithPath() 等函数,允许你进行碰撞检测,以确定图形项是否与其他图形项或路径相交。

  7. 用户数据:你可以附加自定义的用户数据到图形项上,以便在需要时关联额外的信息。

  8. 多选和选择:图形项可以支持多选和选择功能,你可以使用 isSelected() 来检查图形项是否被选择,或使用 setSelected() 来设置图形项的选择状态。

使用示例:

#include <QGraphicsItem>
#include <QPainter>

class MyGraphicsItem : public QGraphicsItem
{
public:
    MyGraphicsItem() { }

    QRectF boundingRect() const override {
        return QRectF(0, 0, 100, 100); // 定义图形项的包围矩形
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override {
        // 在这里进行绘制操作
        painter->setPen(Qt::black);
        painter->setBrush(Qt::blue);
        painter->drawRect(0, 0, 100, 100);
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QGraphicsScene scene;
    MyGraphicsItem *item = new MyGraphicsItem;
    scene.addItem(item);

    QGraphicsView view(&scene);
    view.show();

    return app.exec();
}

四、视图QGraphicsView类

QGraphicsView 类是 Qt 中 GraphicsView 框架的一个核心组件,用于将2D图形场景中的图形项渲染到屏幕上,同时提供了视图操作的功能,如缩放、平移、旋转等。

QGraphicsView 类的主要特性和功能:

  1. 场景显示:QGraphicsView 用于显示 QGraphicsScene 中的图形项,它充当了场景的可视化表示。一个 QGraphicsView 可以关联一个或多个场景,允许你在同一个视图中显示多个场景。

  2. 坐标系:QGraphicsView 具有自己的视图坐标系,这意味着你可以对视图进行缩放、平移和旋转操作,而不影响场景中的图形项。你可以使用 setTransform() 函数来设置视图的变换。

  3. 视图操作:视图允许用户进行交互操作,例如放大、缩小、平移和旋转图形。用户可以使用鼠标或键盘来执行这些操作。视图的滚动条和工具栏通常用于提供这些操作。

  4. 背景和边框:视图可以有自定义的背景和边框,你可以设置视图的背景颜色、图片或渐变,以及边框样式和颜色。

  5. 绘制优化:QGraphicsView 通过使用视图坐标系和场景坐标系之间的坐标转换来实现部分绘制和绘制优化。这有助于提高性能,只有可见部分的图形项会被绘制。

  6. 事件处理:QGraphicsView 可以处理鼠标事件、键盘事件和其他事件,允许用户与图形进行交互。你可以重写视图的事件处理函数以自定义交互行为。

  7. 多视图:你可以创建多个 QGraphicsView 实例并显示相同的或不同的场景。这对于创建多个视图查看同一场景或查看多个场景非常有用。

使用示例:

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QGraphicsScene scene;
    QGraphicsRectItem *rectItem = new QGraphicsRectItem(0, 0, 100, 100);
    scene.addItem(rectItem);

    QGraphicsView view(&scene);
    view.show();

    return app.exec();
}

五、完整示例代码 

继承QGraphicsItem的子类

头文件(.h)

#ifndef PIXITEM_H
#define PIXITEM_H

#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QPixmap>
#include <QPainter>

class PixItem : public QGraphicsItem
{
public:
    explicit PixItem(QPixmap pixmap);

protected:
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;

private:
    QPixmap m_qpix; //作为图元显示对应图片

};

#endif // PIXITEM_H

源文件(.cpp)  

#include "pixitem.h"

PixItem::PixItem(QPixmap pixmap):m_qpix(pixmap)
{

}

QRectF PixItem::boundingRect() const
{
    /*
        QRectF函数:使用浮点精度来定义平面当真的矩形
        对象参数列表,前两个参数是矩形的左上角x和y坐标
        后两个参数宽和高(长度包含七点,所以实际长度减1)
    */
    return QRectF(-2 - m_qpix.width() / 2, -2 - m_qpix.height() / 2, m_qpix.width() + 4, m_qpix.height() + 4);
}

void PixItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    /*
      drawPixmap()使用CPU处理,减轻CPU负担
      QLabel很耗费CPU,播放画面卡顿
    */

    painter->drawPixmap(-(m_qpix.width()) / 2, -(m_qpix.height()) / 2, m_qpix);
}

主程序头文件(.h)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QSlider>
#include <QGroupBox>
#include <math.h>

#include "pixitem.h"

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    void createControlFrame();

private slots:
    void onSliderRotateValue(int value);
    void onSliderScaleValue(int value);
    void onSliderShearValue(int value);

private:
    QGraphicsView *m_pView;
    QFrame *m_pControlFrame;
    PixItem *m_pPixitem;
};
#endif // MAINWINDOW_H

主程序源文件(.cpp)  

#include "main_window.h"

MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle("图形视图");

    QGraphicsScene *pSence = new QGraphicsScene(this);
    pSence->setSceneRect(-200, 200, 400, 400);
    QPixmap pPixmap("D:\\Work\\Code\\GraphicsView\\pexels.jpg");
    m_pPixitem = new PixItem(pPixmap);
    pSence->addItem(m_pPixitem);
    m_pPixitem->setPos(0, 0);

    m_pView = new QGraphicsView(this);
    m_pView->setScene(pSence);
    m_pView->setMinimumSize(800, 600);

    m_pControlFrame = new QFrame(this);
    createControlFrame();

    //主窗口布局
    QHBoxLayout *pHlayout = new QHBoxLayout(this);
    pHlayout->addWidget(m_pView);
    pHlayout->addWidget(m_pControlFrame);
}

MainWindow::~MainWindow()
{
}

void MainWindow::createControlFrame()
{
   //图形旋转
   QSlider *pRotateSlider = new QSlider(this);
   pRotateSlider->setOrientation(Qt::Horizontal);
   pRotateSlider->setRange(0, 360);
   connect(pRotateSlider, &QSlider::sliderMoved, this, &MainWindow::onSliderRotateValue);

   QHBoxLayout *pRotateLayout = new QHBoxLayout(this);
   pRotateLayout->addWidget(pRotateSlider);

   QGroupBox *pRateGroup = new QGroupBox("图形旋转", this);
   pRateGroup->setLayout(pRotateLayout);

   //图形缩放
   QSlider *pScaleSlider = new QSlider(this);
   pScaleSlider->setOrientation(Qt::Horizontal);
   pScaleSlider->setRange(0, 1);
   connect(pScaleSlider, &QSlider::sliderMoved, this, &MainWindow::onSliderScaleValue);

   QHBoxLayout *pScaleLayout = new QHBoxLayout(this);
   pScaleLayout->addWidget(pScaleSlider);

   QGroupBox *pScaleGroup = new QGroupBox("图形缩放", this);
   pScaleGroup->setLayout(pScaleLayout);

   //图形倾斜
   QSlider *pShearSlider = new QSlider(this);
   pShearSlider->setOrientation(Qt::Horizontal);
   pShearSlider->setRange(0, 100);
   connect(pShearSlider, &QSlider::sliderMoved, this, &MainWindow::onSliderShearValue);

   QHBoxLayout *pShearLayout = new QHBoxLayout(this);
   pShearLayout->addWidget(pShearSlider);

   QGroupBox *pShearGroup = new QGroupBox("图形倾斜", this);
   pShearGroup->setLayout(pShearLayout);

   //控制面板设计布局
   QVBoxLayout *pFrameLayout = new QVBoxLayout(this);
   pFrameLayout->addWidget(pRateGroup);
   pFrameLayout->addWidget(pScaleGroup);
   pFrameLayout->addWidget(pShearGroup);

   m_pControlFrame->setLayout(pFrameLayout);
}

//图形旋转
void MainWindow::onSliderRotateValue(int value)
{
    m_pPixitem->setRotation(value);
}

//图形缩放
void MainWindow::onSliderScaleValue(int value)
{
    m_pPixitem->setScale(value);
}

//图形倾斜
void MainWindow::onSliderShearValue(int value)
{
    float floatNumber = static_cast<float>(value);

    QTransform transform;
    transform.shear(floatNumber / 100.0, floatNumber / 100.0); // 0.2 表示20%的倾斜
    m_pPixitem->setTransform(transform);

}

效果展示:  

posted @ 2023-10-26 11:43  TechNomad  阅读(148)  评论(0编辑  收藏  举报