QGraphicsScene主要是什么作用,使用QGraphicsScene画飞控仪表盘

QGraphicsScene主要是什么作用
QGraphicsScene是Qt图形框架中的一个核心类,它主要用于提供一个可以容纳和管理大量2D图形项(QGraphicsItem)的场景。具体来说,QGraphicsScene的作用包括:

1.图形项管理:QGraphicsScene可以管理多个QGraphicsItem对象,您可以在场景中添加、移除和操作这些图形项。它支持添加各种类型的图形项,包括但不限于基本形状(如矩形、圆形等)、图片、文本以及自定义的QGraphicsItem子类。
2.坐标系统:QGraphicsScene使用自己的坐标系统,与窗口或视图的坐标系统分开。这使得在场景中放置和移动图形项更加灵活。
3.事件处理:QGraphicsScene能够处理鼠标事件、键盘事件等,可以捕获这些事件并将它们传递给相应的图形项进行处理,实现交互性。
4.渲染:QGraphicsScene负责管理图形项的绘制,可以将图形项渲染到相关的视图(QGraphicsView)上。
5.选择和焦点:QGraphicsScene支持图形项的选择和焦点管理,可以通过选择和操作图形项来实现交互功能。
6.交互:QGraphicsScene可以处理图形项之间的交互,例如碰撞检测、拖放等。

总的来说,QGraphicsScene为Qt图形视图框架提供了一个强大而灵活的2D图形系统,用于存储、管理和呈现图形项,并支持各种交互和变换操作。

使用QGraphicsScene画飞控仪表盘
Adi.hpp:

#ifndef __qfi_Adi_H__
#define __qfi_Adi_H__

#include <QGraphicsView>
class QWidget;
class QResizeEvent;
class QGraphicsScene;
class QGraphicsSvgItem;
namespace qfi {

//---------------------------------------------------
// Class: Adi
// Description: Attitude Director Indicator
//---------------------------------------------------
class Adi : public QGraphicsView
{
    Q_OBJECT

public:
    Adi(QWidget* parent = nullptr);
    virtual ~Adi();

    // reinitiates widget
    void reinit();

    // refreshes (redraws) widget
    void update();

    void setRoll(const float);
    void setPitch(const float);

protected:
    void resizeEvent(QResizeEvent*);

private:
    void init();
    void reset();
    void updateView();

    QGraphicsScene* m_scene{};

    QGraphicsSvgItem* m_itemBack{};
    QGraphicsSvgItem* m_itemFace{};
    QGraphicsSvgItem* m_itemRing{};
    QGraphicsSvgItem* m_itemCase{};

    float m_roll{};
    float m_pitch{};

    float m_faceDeltaX_new{};
    float m_faceDeltaX_old{};
    float m_faceDeltaY_new{};
    float m_faceDeltaY_old{};

    float m_scaleX{1.0f};
    float m_scaleY{1.0f};

    const int m_originalHeight{240};
    const int m_originalWidth{240};

    const float m_originalPixPerDeg{1.7f};

    QPointF m_originalAdiCtr{120.0f, 120.0f};

    const int m_backZ{-30};
    const int m_faceZ{-20};
    const int m_ringZ{-10};
    const int m_caseZ{10};
};

}

#endif

Adi.cpp:

#include "Adi.hpp"
#include <QGraphicsSvgItem>
#include <cmath>
namespace qfi {

Adi::Adi(QWidget* parent) : QGraphicsView (parent)
{
    m_scene = new QGraphicsScene( this );
    setScene( m_scene );
    m_scene->clear();
    init();
}

Adi::~Adi()
{
    if (m_scene) {
        m_scene->clear();
        delete m_scene;
        m_scene = nullptr;
    }

    reset();
}

void Adi::reinit()
{
    if (m_scene) {
        m_scene->clear();
        init();
    }
}

void Adi::update()
{
    updateView();

    m_faceDeltaX_old  = m_faceDeltaX_new;
    m_faceDeltaY_old  = m_faceDeltaY_new;
}

void Adi::setRoll(const float roll)
{
    m_roll = roll;

    if ( m_roll < -180.0f ) m_roll = -180.0f;
    if ( m_roll >  180.0f ) m_roll =  180.0f;
}

void Adi::setPitch(const float pitch)
{
    m_pitch = pitch;

    if ( m_pitch < -25.0f ) m_pitch = -25.0f;
    if ( m_pitch >  25.0f ) m_pitch =  25.0f;
}

void Adi::resizeEvent(QResizeEvent* event)
{
    QGraphicsView::resizeEvent( event );
    reinit();
}

void Adi::init()
{
    m_scaleX = static_cast<float>(width())  / static_cast<float>(m_originalWidth);
    m_scaleY = static_cast<float>(height()) / static_cast<float>(m_originalHeight);

    reset();

    m_itemBack = new QGraphicsSvgItem( ":/qfi/images/adi/adi_back.svg" );
    m_itemBack->setCacheMode( QGraphicsItem::NoCache );
    m_itemBack->setZValue( m_backZ );
    m_itemBack->setTransform( QTransform::fromScale( m_scaleX, m_scaleY ), true );
    m_itemBack->setTransformOriginPoint( m_originalAdiCtr );
    m_scene->addItem( m_itemBack );

    m_itemFace = new QGraphicsSvgItem( ":/qfi/images/adi/adi_face.svg" );
    m_itemFace->setCacheMode( QGraphicsItem::NoCache );
    m_itemFace->setZValue( m_faceZ );
    m_itemFace->setTransform( QTransform::fromScale( m_scaleX, m_scaleY ), true );
    m_itemFace->setTransformOriginPoint( m_originalAdiCtr );
    m_scene->addItem( m_itemFace );

    m_itemRing = new QGraphicsSvgItem( ":/qfi/images/adi/adi_ring.svg" );
    m_itemRing->setCacheMode( QGraphicsItem::NoCache );
    m_itemRing->setZValue( m_ringZ );
    m_itemRing->setTransform( QTransform::fromScale( m_scaleX, m_scaleY ), true );
    m_itemRing->setTransformOriginPoint( m_originalAdiCtr );
    m_scene->addItem( m_itemRing );

    m_itemCase = new QGraphicsSvgItem( ":/qfi/images/adi/adi_case.svg" );
    m_itemCase->setCacheMode( QGraphicsItem::NoCache );
    m_itemCase->setZValue( m_caseZ );
    m_itemCase->setTransform( QTransform::fromScale( m_scaleX, m_scaleY ), true );
    m_scene->addItem( m_itemCase );

    centerOn( width() / 2.0f , height() / 2.0f );

    updateView();
}

void Adi::reset()
{
    m_itemBack = nullptr;
    m_itemFace = nullptr;
    m_itemRing = nullptr;
    m_itemCase = nullptr;

    m_roll  = 0.0f;
    m_pitch = 0.0f;

    m_faceDeltaX_new = 0.0f;
    m_faceDeltaX_old = 0.0f;
    m_faceDeltaY_new = 0.0f;
    m_faceDeltaY_old = 0.0f;
}

void Adi::updateView()
{
    m_scaleX = static_cast<float>(width())  / static_cast<float>(m_originalWidth);
    m_scaleY = static_cast<float>(height()) / static_cast<float>(m_originalHeight);

    m_itemBack->setRotation(-m_roll);
    m_itemFace->setRotation(-m_roll);
    m_itemRing->setRotation(-m_roll);

    const float roll_rad{static_cast<float>(M_PI * m_roll / 180.0)};
    const float delta{static_cast<float>(m_originalPixPerDeg * m_pitch)};

    m_faceDeltaX_new = m_scaleX * delta * std::sin( roll_rad );
    m_faceDeltaY_new = m_scaleY * delta * std::cos( roll_rad );

    m_itemFace->moveBy( m_faceDeltaX_new - m_faceDeltaX_old, m_faceDeltaY_new - m_faceDeltaY_old );

    m_scene->update();
}

}

同理,画出另外6个仪表盘

最终效果如下:
起飞前的初始状态
在这里插入图片描述

爬升一定高度并倾斜飞行时:
在这里插入图片描述
后续优化方向:
可使用qt 的opengl库和shader库给仪表盘做渲染:

在Qt中使用OpenGL库和shader(着色器)库来为仪表盘(gauge)做渲染是一个常见的图形编程任务。以下是一个基本的步骤指南,用于在Qt应用程序中设置和使用OpenGL进行仪表盘的渲染:

  1. 创建Qt项目:
    使用Qt Creator创建一个新的Qt Widgets应用程序或Qt Quick应用程序(如果你更喜欢使用QML)。
  2. 添加OpenGL支持:
    在Qt Widgets应用程序中,你可以通过继承QOpenGLWidget或QOpenGLWindow类来添加OpenGL支持。
    对于Qt Quick应用程序,你可以在QML文件中使用Canvas元素,并通过JavaScript调用OpenGL ES 2.0 API,或者使用Qt 3D模块。
  3. 编写着色器代码:
    编写顶点着色器(Vertex Shader)和片段着色器(Fragment Shader)代码。这些着色器定义了如何从顶点数据生成图形,以及如何为图形的每个像素着色。
    将着色器代码保存为.glsl文件,或在代码中直接作为字符串包含。
  4. 加载和编译着色器:
    在你的OpenGL代码中,加载顶点着色器和片段着色器的源代码。
    使用OpenGL的API(如glCreateShader、glShaderSource、glCompileShader等)来编译和链接着色器程序。
  5. 设置顶点数据:
    创建一个包含仪表盘顶点数据的缓冲区对象(VBO)。这可以包括仪表盘的外轮廓、刻度、指针等。
    使用OpenGL的API(如glGenBuffers、glBindBuffer、glBufferData等)来创建和填充VBO。
  6. 渲染仪表盘:
    在你的OpenGL渲染循环中(通常在QOpenGLWidget的paintGL函数中),清除屏幕,绑定着色器程序,并设置任何必要的变换矩阵。
    启用顶点数组和顶点缓冲区对象,并调用glDrawArrays或glDrawElements来渲染仪表盘。
  7. 添加交互性:
    如果你的仪表盘需要交互性(例如,旋转指针或选择刻度),你可以处理鼠标或触摸事件,并更新仪表盘的状态。
    在渲染循环中,根据当前状态更新仪表盘的渲染。
  8. 优化和调试:
    使用OpenGL的调试工具(如GL_DEBUG_OUTPUT)来检测和修复渲染问题。
    优化你的着色器代码和顶点数据,以提高渲染性能。
  9. 集成到Qt应用程序中:
    将你的OpenGL渲染代码集成到你的Qt应用程序中。这可能涉及在Qt的窗口系统中创建和管理OpenGL上下文。
    确保你的OpenGL代码与Qt的事件循环和窗口系统正确交互。

附录:GraphicView,GraphicScene,GraphicItem的关系是什么
GraphicsView、GraphicsScene 和 GraphicsItem 是 Qt 框架中 Graphics View 框架的三个核心概念,它们各自具有不同的功能和用法。以下是它们之间的区别和简要说明:

GraphicsView(视图):
GraphicsView 是用于显示 GraphicsScene(场景)的窗口或部件。
它提供了一个视口,用户可以通过该视口查看和管理 GraphicsScene 中的 GraphicsItem(图形项)。
GraphicsView 支持缩放、平移、旋转等视图操作,以便用户可以更好地查看和交互场景中的图形项。
你可以通过重写 GraphicsView 的事件处理函数来自定义视图的交互行为。

GraphicsScene(场景):
GraphicsScene 是一个容器,用于管理 GraphicsItem(图形项)。
你可以将 GraphicsScene 想象为一个虚拟的画布,你可以在其中添加、删除和管理多个图形项。
它提供了管理大量图元的快速接口,并传播鼠标、键盘等事件给场景中的每个图元。
GraphicsScene 还支持图元状态的管理,如图元选择和焦点处理,以及无变换的渲染功能(如打印)。
你可以使用 QGraphicsScene::addItem() 方法将图形项添加到场景中。

GraphicsItem(图形项):
GraphicsItem 是在 GraphicsScene(场景)中显示的图形元素。
它可以是各种类型的图形项,包括基本形状(如矩形、圆形等)、图片、文本以及自定义的 QGraphicsItem 子类。
GraphicsItem 提供了一种方法来管理图形项的位置、外观、交互等属性,使其能够在图形视图框架中进行显示和交互。
你可以使用 QGraphicsItem 及其派生类来创建可在图形场景中显示的图形元素,并处理图形项的交互事件,如鼠标点击、拖动等。

总结:GraphicsView 是用于显示 GraphicsScene 的窗口或部件,GraphicsScene 是用于管理 GraphicsItem 的容器,而 GraphicsItem 则是在 GraphicsScene 中显示的图形元素。它们共同构成了 Qt 框架中 Graphics View 框架用于创建复杂的图形用户界面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值