【QOpenGL实践】QOpenGLWidget

目录

一、说明

二、QOpenGLWidget 类对象

2.1 概要 

2.1.1 函数功能 

 2.1. 2 三个虚函数

 2.1.3 信号

 2.2 详细说明

2.2.1  三个虚函数

2.2.2 绘画技巧

2.2.3 OpenGL 函数调用、标头和 QOpenGLFunctions 

三、实现代码示例

3.1 最简模式

3.2 与 QGLWidget 的关系

3.3 与 QGLWidget 的差异

 3.4 多重采样

3.5 线程化

3.6 上下文共享

四、资源初始化和清理

五、局限性 


一、说明

        据说QOpenGLWidget是用来取代QGLWidget的继承者,我们通过多次尝试,发现QGLWidget的鲁棒性很差,用来开发游戏,其步履和亚马逊泥沼中行走有类同,谈不上体验,只能叫半成品的测试。从本文之后,我们将尝试QOpenGLWidget,看看是不是人类的曙光再次诞临,若不是也不必太勉强了。用用GLUT或pygame也能度过。

二、QOpenGLWidget 类对象

        该类 QOpenGLWidget是用于渲染 OpenGL 图形的小部件。更多的…

PySide2.QtWidgets.QOpenGLWidget的继承图

2.1 概要 

2.1.1 函数功能 

  • 定义context()

  • 定义defaultFramebufferObject()

  • 定义doneCurrent()

  • 定义format()

  • 定义grabFramebuffer()

  • 定义isValid()

  • 定义makeCurrent()

  • 定义setFormat(格式)

  • def setTextureFormat(tex 格式)

  • def setUpdateBehavior(更新行为)

  • 定义textureFormat()

  • 定义updateBehavior()

 2.1. 2 三个虚函数

  • 定义initializeGL()

  • 定义paintGL()

  • 定义resizeGL(宽,高)

 2.1.3 信号

  • 定义aboutToCompose()

  • 定义aboutToResize()

  • 定义frameSwapped()

  • 定义resized()

 2.2 详细说明

2.2.1  三个虚函数

QOpenGLWidget提供集成到 Qt 应用程序中的显示 OpenGL 图形的功能。它使用起来非常简单:QPainter让你的类继承它并像任何其他类一样使用子类,除了你可以在使用和标准 OpenGL 渲染命令QWidget之间进行选择。

QOpenGLWidget提供了三个方便的虚拟函数,您可以在子类中重新实现它们来执行典型的 OpenGL 任务:

  • paintGL()- 渲染 OpenGL 场景。每当小部件需要更新时就会被调用。

  • resizeGL()- 设置 OpenGL 视口、投影等。每当调整窗口小部件的大小时(以及第一次显示窗口小部件时,因为所有新创建的窗口小部件都会自动获取调整大小事件),都会调用它。

  • initializeGL()- 设置 OpenGL 资源和状态。在第一次之前被呼叫一次resizeGL()或被paintGL()呼叫。

        如果您需要从其他地方触发重绘paintGL()(典型的例子是用于timers动画场景时),您应该调用小部件的update()函数来安排更新。

当调用paintGL()、resizeGL()或时,您的小部件的 OpenGL 渲染上下文将变为当前上下文。initializeGL()如果您需要从其他地方调用标准 OpenGL API 函数(例如,在您的小部件的构造函数中或在您自己的绘制函数中),您必须makeCurrent()首先调用。

        所有渲染都发生在 OpenGL 帧缓冲区对象中。makeCurrent()确保它在上下文中绑定。在渲染代码中创建和绑定附加帧缓冲区对象时请记住这一点paintGL()。切勿重新绑定 ID 为 0 的帧缓冲区。而是调用defaultFramebufferObject()以获取应绑定的 ID。

QOpenGLWidget当平台支持时,允许使用不同的 OpenGL 版本和配置文件。只需通过设置请求的格式即可setFormat()。但请记住,QOpenGLWidget在同一窗口中拥有多个实例要求它们全部使用相同的格式,或者至少使用不会使上下文不可共享的格式。为了解决这个问题,最好使用setDefaultFormat()而不是setFormat().

笔记

在某些平台(例如 macOS)上,当请求 OpenGL 核心配置文件上下文时,必须setDefaultFormat()在构造实例之前进行调用。QApplication这是为了确保上下文之间的资源共享保持功能,因为所有内部上下文都是使用正确的版本和配置文件创建的。

2.2.2 绘画技巧

如上所述,QOpenGLWidget通过以下方式子类化渲染纯 3D 内容:

  • 重新实现initializeGL()和resizeGL()函数来设置 OpenGL 状态并提供透视变换。

  • 重新实现paintGL()绘制 3D 场景,仅调用 OpenGL 函数。

还可以QOpenGLWidget使用以下方法将 2D 图形绘制到子类上QPainter

  • 在 中paintGL(),不是发出 OpenGL 命令,而是构造一个QPainter在小部件上使用的对象。

  • QPainter使用 的成员函数绘制基元。

  • 仍然可以发出直接 OpenGL 命令。但是,您必须确保它们包含在对画家的 beginNativePainting() 和 endNativePainting() 的调用中。

当仅使用执行绘制时QPainter,也可以像普通小部件一样执行绘制:通过重新实现paintEvent().

  • 重新实现该paintEvent()功能。

  • 构造一个QPainter针对小部件的对象。将小部件传递给构造函数或begin()函数。

  • QPainter使用 的成员函数绘制基元。

  • 绘画完成后QPainter实例被销毁。或者,end()显式调用。

2.2.3 OpenGL 函数调用、标头和 QOpenGLFunctions 

        在进行 OpenGL 函数调用时,强烈建议避免直接调用函数。相反,更喜欢使用QOpenGLFunctions(在制作便携式应用程序时)或版本化变体(例如,QOpenGLFunctions_3_2_Core当针对现代的、仅限桌面的 OpenGL 时,类似的)。这样,应用程序将在所有 Qt 构建配置中正常工作,包括执行动态 OpenGL 实现加载的配置,这意味着应用程序不直接链接到 GL 实现,因此直接函数调用不可行。

        在paintGL()当前上下文中始终可以通过 caling 访问currentContext()。在此上下文中QOpenGLFunctions,可以通过调用 来检索已初始化的、可供使用的实例functions()。为每个 GL 调用添加前缀的替代方法是继承QOpenGLFunctionsinitializeOpenGLFunctions()调用initializeGL().

        至于 OpenGL 标头,请注意,在大多数情况下,不需要直接包含任何标头(例如 GL.h)。与 OpenGL 相关的 Qt 头文件将包括 qopengl.h,而 qopengl.h 又将包括适合系统的头文件。这可能是 OpenGL ES 3.x 或 2.0 标头、可用的最高版本或系统提供的 gl.h。此外,扩展头文件的副本(在某些系统上称为 glext.h)作为 Qt 的一部分提供,适用于 OpenGL 和 OpenGL ES。在可行的情况下,这些将自动包含在平台上。这意味着来自 ARB、EXT、OES 扩展的常量和函数指针类型定义自动可用。

三、实现代码示例

3.1 最简模式

首先,最简单的QOpenGLWidget子类可能如下所示:

class MyGLWidget : public QOpenGLWidget
{
public:
    MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }

protected:
    void initializeGL() override
    {
        // Set up the rendering context, load shaders and other resources, etc.:
        QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
        f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        ...
    }

    void resizeGL(int w, int h) override
    {
        // Update projection matrix and other size related settings:
        m_projection.setToIdentity();
        m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
        ...
    }

    void paintGL() override
    {
        // Draw the scene:
        QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
        f->glClear(GL_COLOR_BUFFER_BIT);
        ...
    }

};

        或者,可以通过派生来避免每个 OpenGL 调用的前缀QOpenGLFunctions

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    ...
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(...);
        ...
    }
    ...
};

        要获得与给定 OpenGL 版本或配置文件兼容的上下文,或者请求深度和模板缓冲区,请调用setFormat():

QOpenGLWidget *widget = new QOpenGLWidget(parent);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
widget->setFormat(format); // must be called before the widget or its parent window gets shown

        在 OpenGL 3.0+ 上下文中,当可移植性并不重要时,版本化QOpenGLFunctions变体可以轻松访问给定版本中可用的所有现代 OpenGL 函数:

 
void paintGL() override
{
    QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
    ...
    f->glDrawArraysInstanced(...);
    ...
}
 

        如上所述,全局设置请求的格式更简单且更稳健,以便它在应用程序的生命周期内应用于所有窗口和上下文。下面是一个例子:

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

    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setVersion(3, 2);
    format.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(format);

    MyWidget widget;
    widget.show();

    return app.exec();
}

3.2 与 QGLWidget 的关系

遗留的QtOpenGL模块(以 QGL 为前缀的类)提供了一个名为 的小部件QGLWidget。QOpenGLWidget旨在成为它的现代替代品。因此,特别是在新的应用中,一般建议使用QOpenGLWidget.

虽然 API 非常相似,但两者之间有一个重要的区别:QOpenGLWidget始终使用帧缓冲区对象在屏幕外渲染。QGLWidget另一方面使用本机窗口和表面。后者在复杂的用户界面中使用它时会引起问题,因为根据平台的不同,此类本机子小部件可能具有各种限制,例如关于堆叠顺序的限制。QOpenGLWidget通过不创建单独的本机窗口来避免这种情况。

由于由帧缓冲区对象支持, 的行为与设置为或 的更新行为QOpenGLWidget非常相似。这意味着内容在调用之间被保留,以便增量渲染成为可能。使用(当然也使用默认的更新行为)通常情况并非如此,因为交换缓冲区会使后台缓冲区留下未定义的内容。QOpenGLWindowPartialUpdateBlitPartialUpdateBlendpaintGL()QGLWidgetQOpenGLWindow

笔记

大多数应用程序不需要增量渲染,因为它们将在每次绘制调用时渲染视图中的所有内容。在这种情况下,尽早在paintGL().这有助于使用基于图块的架构的移动 GPU 认识到图块缓冲区不需要重新加载帧缓冲区的先前内容。省略clear调用可能会导致此类系统的性能显着下降。

笔记

避免winId()调用QOpenGLWidget.此函数会触发本机窗口的创建,从而导致性能下降并可能出现渲染故障。

3.3 与 QGLWidget 的差异

QOpenGLWidget除了由帧缓冲区对象支持的主要概念差异之外,旧版本之间还存在许多较小的内部差异QGLWidget

  • 调用时的 OpenGL 状态paintGL()。QOpenGLWidget通过 glViewport() 设置视口。它不执行任何清除操作。

  • 开始通过 绘制时清除QPainter。与常规小部件不同,QGLWidget默认值为truefor autoFillBackground。然后,每次begin()使用时都会对调色板的背景颜色执行清除操作。QOpenGLWidget不遵循这个:autoFillBackground默认为 false,就像任何其他小部件一样。唯一的例外是用作其他小部件(例如QGraphicsView.在这种情况下autoFillBackground将自动设置为 true 以确保与QGLWidget基于视口的兼容性。

 3.4 多重采样

        QSurfaceFormat要启用多重采样,请在传递给 的上设置请求的样本数setFormat()。在不支持它的系统上,该请求可能会被忽略。

多重采样支持需要支持多重采样渲染缓冲区和帧缓冲区位块传送。在 OpenGL ES 2.0 实现中,这些可能不会出现。这意味着多重采样将不可用。对于现代 OpenGL 版本和 OpenGL ES 3.0 及更高版本,这通常不再是问题。

3.5 线程化

paintGL()通过公开小部件来支持在工作线程上执行离屏渲染,例如生成随后在 GUI/主线程中使用的纹理,QOpenGLContext以便可以在每个线程上创建与其共享的其他上下文。

通过重新实现不执行任何操作,QOpenGLWidget可以直接绘制到GUI/主线程外部的帧缓冲区。paintEvent()上下文的线程关联性必须通过更改moveToThread()。之后,makeCurrent()和doneCurrent()可在工作线程上使用。之后请小心将上下文移回 GUI/主线程。

与 不同的是QGLWidget,仅针对 触发缓冲区交换QOpenGLWidget是不可能的,因为它没有真正的屏幕本机表面。相反,由小部件堆栈来管理 GUI 线程上的组​​合和缓冲区交换。当线程完成帧缓冲区更新后,调用GUI/主线程来安排合成。update()

当 GUI/主线程执行合成时,必须格外小心,避免使用帧缓冲区。当乐曲开始和结束时,将发出aboutToCompose()和信号。frameSwapped()它们在 GUI/主线程上发出。这意味着通过使用直接连接aboutToCompose()可以阻塞 GUI/主线程,直到工作线程完成渲染。之后,工作线程必须不再执行渲染,直到frameSwapped()发出信号为止。如果这是不可接受的,工作线程必须实现双缓冲机制。这涉及使用完全由线程控制的替代渲染目标(例如附加的帧缓冲区对象)进行绘制,并QOpenGLWidget在适当的时间位块传输到 的帧缓冲区。

3.6 上下文共享

当多个 QOpenGLWidget 作为子级添加到同一个顶级 widget 时,它们的上下文将相互共享。这不适用于QOpenGLWidget属于不同窗口的实例。

这意味着同一窗口中的所有 QOpenGLWidget 都可以访问彼此的可共享资源,例如纹理,并且不需要额外的“全局共享”上下文,就像QGLWidget.

QOpenGLWidget要在属于不同窗口的实例之间设置共享,请AA_ShareOpenGLContexts在实例化之前设置应用程序属性QApplication。这将触发所有QOpenGLWidget实例之间的共享,无需任何进一步的步骤。

QOpenGLContext创建与 的上下文共享纹理等资源的额外实例QOpenGLWidget也是可能的。只需在调用之前传递从context()to返回的指针即可。生成的上下文还可以在不同的线程上使用,从而允许线程化纹理生成和异步纹理上传。setShareContext()create()

请注意,QOpenGLWidget当涉及底层图形驱动程序时,期望资源共享的标准一致实现。例如,某些驱动程序(特别是针对移动和嵌入式硬件的驱动程序)在现有上下文和以后创建的其他上下文之间设置共享时存在问题。当尝试利用不同线程之间的共享资源时,其他一些驱动程序可能会以意想不到的方式运行。

四、资源初始化和清理

        无论何时调用和 ,的关联 OpenGL上下文QOpenGLWidget都保证是最新的。在调用之前不要尝试创建 OpenGL 资源。例如,在子类的构造函数中尝试编译着色器、初始化顶点缓冲区对象或上传纹理数据将失败。这些操作必须推迟到。一些 Qt 的 OpenGL 帮助器类(例如或)具有匹配的延迟行为:它们可以在没有上下文的情况下实例化,但所有初始化都会延迟到或类似的调用。这意味着它们可以用作子类中的普通(非指针)成员变量,但只能从.但请注意,并非所有类都是这样设计的。如有疑问,请将成员变量设置为指针,并分别在析构函数中动态创建和销毁实例。initializeGL()paintGL()initializeGL()initializeGL()QOpenGLBufferQOpenGLVertexArrayObjectcreate()QOpenGLWidgetcreate()initializeGL()initializeGL()

        释放资源还需要当前上下文。因此,执行此类清理的析构函数预计会makeCurrent()在继续销毁任何 OpenGL 资源或包装器之前调用。避免通过deleteLater()或 的育儿机制进行延迟删除QObject。无法保证在相关实例真正被销毁时正确的上下文将是当前的。

因此,在资源初始化和销毁​​方面,典型的子类通常如下所示:

class MyGLWidget : public QOpenGLWidget
{
    ...

private:
    QOpenGLVertexArrayObject m_vao;
    QOpenGLBuffer m_vbo;
    QOpenGLShaderProgram *m_program;
    QOpenGLShader *m_shader;
    QOpenGLTexture *m_texture;
};

MyGLWidget::MyGLWidget()
    : m_program(0), m_shader(0), m_texture(0)
{
    // No OpenGL resource initialization is done here.
}

MyGLWidget::~MyGLWidget()
{
    // Make sure the context is current and then explicitly
    // destroy all underlying OpenGL resources.
    makeCurrent();

    delete m_texture;
    delete m_shader;
    delete m_program;

    m_vbo.destroy();
    m_vao.destroy();

    doneCurrent();
}

void MyGLWidget::initializeGL()
{
    m_vao.create();
    if (m_vao.isCreated())
        m_vao.bind();

    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(...);

    m_texture = new QOpenGLTexture(QImage(...));

    m_shader = new QOpenGLShader(...);
    m_program = new QOpenGLShaderProgram(...);

    ...
}

        这自然不是唯一可能的解决方案。一种替代方法是使用aboutToBeDestroyed()的信号QOpenGLContext。通过使用直接连接将插槽连接到此信号,每当QOpenGLContext要释放底层本机上下文句柄或整个实例时,就可以执行清理。以下代码片段原则上与上一个代码片段等效:

void MyGLWidget::initializeGL()
{
    // context() and QOpenGLContext::currentContext() are equivalent when called from initializeGL or paintGL.
    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
}

void MyGLWidget::cleanup()
{
    makeCurrent();
    delete m_texture;
    m_texture = 0;
    ...
    doneCurrent();
}
        对于在其生命周期内多次更改其关联的顶级窗口的小部件,组合方法至关重要。每当小部件或其父级重新设置父级以使顶级窗口变得不同时,小部件的关联上下文就会被销毁并创建一个新的上下文。然后调用initializeGL()所有 OpenGL 资源必须重新初始化的位置。因此,执行正确清理的唯一选择是连接到上下文的 aboutToBeDestroyed() 信号。请注意,当信号发出时,所讨论的上下文可能不是当前的上下文。因此,最好的做法是调用makeCurrent()已连接的槽。此外,必须从派生类的析构函数执行相同的清理步骤,因为当小部件被销毁时,连接到信号的槽将不会被调用。

        注意:

        设置后AA_ShareOpenGLContexts,小部件的上下文永远不会更改,即使在重新设置父级时也不会更改,因为保证也可以从新的顶级上下文访问小部件的关联纹理。

由于上下文共享,正确的清理尤为重要。即使每个QOpenGLWidget的关联上下文与 一起被销毁QOpenGLWidget,该上下文中的可共享资源(如纹理)将保持有效,直到其中存在的顶级窗口QOpenGLWidget被销毁。此外,诸如某些 Qt 模块之类的设置AA_ShareOpenGLContexts可能会触发更广泛的共享上下文,从而可能导致相关资源在应用程序的整个生命周期内保持活动状态。因此,最安全、最稳健的方法始终是对QOpenGLWidget.

五、局限性 

        将其他小部件放在下面并使其QOpenGLWidget透明不会导致预期的结果:下面的小部件将不可见。这是因为实际上QOpenGLWidget是在所有其他常规非 OpenGL 小部件之前绘制的,因此透视类型的解决方案是不可行的。其他类型的布局,例如在 之上放置小部件QOpenGLWidget,将按预期运行。

        当绝对必要时,可以通过WA_AlwaysStackOnTop在QOpenGLWidget.但请注意,这会破坏堆叠顺序,例如,不可能在 的顶部放置其他小部件,因此它只能在需要QOpenGLWidget半透明且其他小部件在下面可见的情况下使用。QOpenGLWidget

请注意,当下面没有其他小部件并且目的是拥有半透明窗口时,这并不适用。在这种情况下WA_TranslucentBackground,在顶层窗口上进行设置的传统方法就足够了。请注意,如果仅需要透明区域QOpenGLWidget,则启用后WA_NoSystemBackground需要将其转回。此外,根据系统的不同,可能还需要为的上下文请求 alpha 通道。falseWA_TranslucentBackgroundQOpenGLWidgetsetFormat()

QOpenGLWidget支持多种更新行为,就像QOpenGLWindow.在保留模式下,上一次调用的渲染内容paintGL()可在下一次调用中使用,从而允许增量渲染。在非保留模式下,内容会丢失,并且paintGL()预计实现会重绘视图中的所有内容。

在 Qt 5.5 之前,默认行为是在调用QOpenGLWidget之间保留渲染的内容paintGL()。自 Qt 5.5 起,默认行为不再保留,因为这提供了更好的性能,并且大多数应用程序不需要以前的内容。这也类似于基于 OpenGL 的语义,并且与每个帧的颜色和辅助缓冲区无效的QWindow默认行为相匹配。QOpenGLWindow要恢复保留的行为,请setUpdateBehavior()使用 进行调用PartialUpdate

        注意

        由于与其他基于内容的组合的工作方式,显示QOpenGLWidget需要在关联的顶级窗口的后备存储中使用 Alpha 通道QWidget。如果没有alpha通道,渲染的内容QOpenGLWidget将不可见。当使用低于 24 的颜色深度时,这在远程显示设置(例如使用 Xvnc)中的 Linux/X11 上尤其重要。例如,16 的颜色深度通常会映射到使用具有以下格式的后备存储图像Format_RGB16(RGB565),没有为 Alpha 通道留下空间。因此,如果在与窗口中的其他小部件正确获取合成内容时遇到问题QOpenGLWidget,请确保服务器(例如 vncserver)配置为 24 或 32 位深度而不是 16 位深度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/552786.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode———144—— 二叉树的前序遍历

目录 ​编辑 1.题目 2.解答 1.首先计算二叉树的节点个数&#xff1a; 2.以先序遍历&#xff08;Preorder Traversal&#xff09;的方式遍历一个二叉树&#xff0c;并将遍历到的节点的值存储在一个整数数组中 3.最终代码 1.题目 . - 力扣&#xff08;LeetCode&#xff09; 给…

123页|华为项目管理精华-成功的项目管理(免费下载)

【1】关注本公众号&#xff0c;转发当前文章到微信朋友圈 【2】私信发送 华为项目管理精华 【3】获取本方案PDF下载链接&#xff0c;直接下载即可。 如需下载本方案PPT原格式&#xff0c;请加入微信扫描以下方案驿站知识星球&#xff0c;获取上万份PPT解决方案&#xff01;&a…

IDEA Tomcat localhost 日志和 catalina日志乱码(解决)

只需要修改 Tomcat 的 logging.properties D:\work\apache-tomcat-8.5.70-windows-x64\apache-tomcat-8.5.70\conf

SpringMVC 常用注解介绍

Spring MVC 常用注解介绍 文章目录 Spring MVC 常用注解介绍准备1. RequestMapping1.1 介绍2.2 注解使用 2. 请求参数2.1 传递单个参数2.2 传递多个参数2.3 传递对象2.4 传递数组 3. RequestParam3.1 注解使用3.2 传入集合 4. RequestBody5. PathVariable6. RequestPart7. Rest…

Since Maven 3.8.1 http repositories are blocked.

编译maven 项目时候报错提示下面信息&#xff1a; Since Maven 3.8.1 http repositories are blocked.Possible solutions: - Check that Maven settings.xml does not contain http repositories - Check that Maven pom files do not contain http repository http://XXXXXX:…

Mac电脑上有什么好玩的格斗游戏 《真人快打1》可以在苹果电脑上玩吗

你是不是喜欢玩格斗游戏&#xff1f;你是不是想在你的Mac电脑上体验一些刺激和激烈的对战&#xff1f;在这篇文章中&#xff0c;我们将介绍Mac电脑上有什么好玩的格斗游戏&#xff0c;以及《真人快打1》可以在苹果电脑上玩吗。 一、Mac电脑上有什么好玩的格斗游戏 格斗游戏是…

设计循环队列(队列oj)

1.设计循环队列 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。…

如何在原生项目中集成flutter

两个前提条件&#xff1a; 从flutter v1.17版本开始&#xff0c;flutter module仅支持AndroidX的应用在release模式下flutter仅支持一下架构&#xff1a;x84_64、armeabi-v7a、arm6f4-v8a,不支持mips和x86;所以引入flutter前需要在app/build.gradle下配置flutter支持的架构 a…

Jmeter 压测-Jprofiler定位接口相应时间长

1、环境准备 执行压测脚本&#xff0c;分析该接口tps很低&#xff0c;响应时间很长 高频接口在100ms以内&#xff0c;普通接口在200ms以内 2、JProfiler分析响应时间长的方法 ①JProfiler录制数据 压测脚本&#xff0c;执行1-3分钟即可 ②分析接口相应时间长的方法 通过Me…

全国产化无风扇嵌入式车载电脑在车队管理嵌入式车载行业应用

车队管理嵌入式车载行业应用 车队管理方案能有效解决车辆繁多管理困难问题&#xff0c;配合调度系统让命令更加精确有效执行。实时监控车辆状况、行驶路线和位置&#xff0c;指导驾驶员安全有序行驶&#xff0c;有效降低保险成本、事故概率以及轮胎和零部件的磨损与损坏。 方…

vue3第二十节(新增编译宏defineModel)

为什么会需要使用defineModel() 注意&#xff1a;defineModel() 需要在3.4及以上版本才可使用&#xff1b; 组件之间通讯&#xff0c;通过 props 和 emits 进行通讯,是单向数据流&#xff0c;比如&#xff1a;props是自上而下的&#xff08;父组件数据修改导致子组件更新&…

企业网站制作如何被百度收录

1、网站在百度中的整体评分 说俗点就是网站的权重&#xff0c;在优化过程中我们会见到很多网站出现秒收的情况&#xff0c;发布的文章几分钟就可以收录&#xff0c;这个通过SITE语法都可以去查询&#xff0c;那么这跟自己的网站权重以及内容更新习惯是有非常重要的关联。 我们…

每日OJ题_完全背包④_力扣279. 完全平方数(一维和二维)

目录 力扣279. 完全平方数 问题解析 解析代码 优化代码&#xff08;相同子问题分析和滚动数组&#xff09; 力扣279. 完全平方数 279. 完全平方数 难度 中等 给你一个整数 n &#xff0c;返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数&#xff0c;其值…

《论文阅读》基于情感原因感知的共情对话生成模型 2023 AAAI

《论文阅读》基于情感原因感知的共情对话生成模型 2023 AAAI 前言简介模型构架情绪推理器回复生成器实验结果前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《The Empathic Dialogue Generation Model…

如何使用自定义Promptbooks优化您的安全工作流程

在当今的数字化时代&#xff0c;安全工作流程的优化变得前所未有的重要。安全团队需要快速、有效地响应安全事件&#xff0c;以保护组织的数据和资产。Microsoft Copilot for Security提供了一种强大的工具——自定义Promptbooks&#xff0c;它可以帮助安全专家通过自动化和定制…

type-cDP输入转双type-cDP输出,加type-c接口充电管理同时接两台显示器或者VR投屏,龙迅LT8712SX方案,龙迅桥接芯片方案

type-c的应用在各种设备上更加广泛&#xff0c;包括手机&#xff0c;电脑&#xff0c;游戏掌机&#xff0c; 因为type-c的功能非常强大&#xff0c;可以做到PD快充&#xff0c;DP信号输出&#xff0c;USB信号输出&#xff0c;所以很多设备为了做得更简洁都开始把其他的如HDMI接…

谈谈我的实习生活

距离实习已经过去快一年了&#xff0c;说真的&#xff0c;很多关于实习的事情我都已经忘记了。今天正好我有空&#xff0c;就想着写一些东西&#xff0c;思来想去&#xff0c;就想着要不把实习的生活给记录下来&#xff0c;就当给自己留一个回忆&#xff0c;毕竟这也是我人生中…

ARM作业day8

温湿度数据采集应用&#xff1a; 由上图可知&#xff1a; 控制温湿度采集模块的引脚是PF14&#xff08;串行时钟线&#xff09;和PF15&#xff08;串行数据线&#xff09;&#xff1a;控制温湿度采集模块的总线是AHB4&#xff0c;通过GPIOF串口和RCC使能完成初始化操作。 控制…

springboot2集成东方通tongweb嵌入式版

由于最近项目需要国产化信创改造&#xff0c;引入东方通tongweb 联系东方通厂家 &#xff0c;将依赖导入到maven仓库&#xff0c;并获取嵌入式版license文件修改pom.xml&#xff0c;引入依赖&#xff0c;注意springboot版本&#xff0c;这里以springboot2举例 首先移除springb…

C++设计模式|创建型 3.抽象工厂模式

在上一篇文章中介绍了工厂模式&#xff0c;每个具体工厂负责生产一个专门的产品&#xff0c;其代码扩展性很好&#xff0c;这篇文章将介绍抽象工厂模式。 1.为什么要使用抽象工厂模式&#xff1f; 既然已经有了“工厂模式”&#xff0c;那为什么还会有抽象工厂模式呢&#xf…