Qt5下OpenGL程序的新写法

本文提供两种Qt5中OpenGL程序的模板示例,一种直接继承QWindow并使用QOpenGLFunctions,另一种则通过分离渲染器和窗口的方式实现。示例详细展示了如何初始化OpenGL上下文、设置格式以及进行渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Qt5中,引入了QOpenGL*系列类,以取代Qt4时代的QGL*系列类。


下面是从Qt5例子中抠出的两种OpenGL程序模板,方便参考。


第一种写法:

[cpp]  view plain  copy
  1. #ifndef TRIANGLEWINDOW_H  
  2. #define TRIANGLEWINDOW_H  
  3.   
  4. #include <QWindow>  
  5. #include <QOpenGLFunctions>  
  6.   
  7. class QPainter;  
  8. class QOpenGLContext;  
  9. class QOpenGLPaintDevice;  
  10.   
  11. class TriangleWindow : public QWindow, protected QOpenGLFunctions  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit TriangleWindow(QWindow *parent = 0);  
  16.     ~TriangleWindow();  
  17.       
  18.     virtual void render(QPainter *);  
  19.     virtual void render();  
  20.     virtual void initialize();  
  21.       
  22. public slots:  
  23.     void renderNow();  
  24.   
  25. protected:  
  26.     void exposeEvent(QExposeEvent *);  
  27.     void resizeEvent(QResizeEvent *);  
  28.   
  29. private:  
  30.     bool m_update_pending;  
  31.   
  32.     QOpenGLContext *m_context;  
  33.     QOpenGLPaintDevice *m_device;  
  34.       
  35. };  
  36.   
  37. #endif // TRIANGLEWINDOW_H  

实现代码如下:

[cpp]  view plain  copy
  1. #include "trianglewindow.h"  
  2.   
  3. #include <QCoreApplication>  
  4. #include <QPainter>  
  5. #include <QOpenGLContext>  
  6. #include <QOpenGLPaintDevice>  
  7.   
  8. TriangleWindow::TriangleWindow(QWindow *parent) :  
  9.     QWindow(parent)  
  10.   , m_update_pending(false)  
  11.   , m_context(0)  
  12.   , m_device(0)  
  13. {  
  14.     setSurfaceType(QWindow::OpenGLSurface);  
  15. }  
  16.   
  17. TriangleWindow::~TriangleWindow()  
  18. {  
  19.     delete m_device;  
  20. }  
  21.   
  22. void TriangleWindow::render(QPainter *painter)  
  23. {  
  24.     Q_UNUSED(painter);  
  25. }  
  26.   
  27. void TriangleWindow::render()  
  28. {  
  29.     if (!m_device)  
  30.         m_device = new QOpenGLPaintDevice;  
  31.   
  32.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);  
  33.   
  34.     m_device->setSize(size());  
  35.   
  36.     QPainter painter(m_device);  
  37.     render(&painter);  
  38. }  
  39.   
  40. void TriangleWindow::initialize()  
  41. {  
  42.     glClearColor(1, 0, 0, 1);  
  43. }  
  44.   
  45. void TriangleWindow::renderNow()  
  46. {  
  47.     if (!isExposed())  
  48.         return;  
  49.   
  50.     m_update_pending = false;  
  51.   
  52.     bool needsInitialize = false;  
  53.   
  54.     if (!m_context) {  
  55.         m_context = new QOpenGLContext(this);  
  56.         m_context->setFormat(requestedFormat());  
  57.         m_context->create();  
  58.   
  59.         needsInitialize = true;  
  60.     }  
  61.   
  62.     m_context->makeCurrent(this);  
  63.   
  64.     if (needsInitialize) {  
  65.         initializeOpenGLFunctions();  
  66.         initialize();  
  67.     }  
  68.   
  69.     render();  
  70.   
  71.     m_context->swapBuffers(this);  
  72. }  
  73.   
  74. void TriangleWindow::exposeEvent(QExposeEvent *event)  
  75. {  
  76.     Q_UNUSED(event);  
  77.   
  78.     if (isExposed())  
  79.         renderNow();  
  80. }  
  81.   
  82. void TriangleWindow::resizeEvent(QResizeEvent *event)  
  83. {  
  84.     Q_UNUSED(event);  
  85.   
  86.     if (isExposed())  
  87.         renderNow();  
  88. }  

main方法:

[cpp]  view plain  copy
  1. #include "trianglewindow.h"  
  2.   
  3. #include <QGuiApplication>  
  4.   
  5. int main(int argc, char **argv)  
  6. {  
  7.     QGuiApplication app(argc, argv);  
  8.   
  9.     QSurfaceFormat format;  
  10.     format.setSamples(4);  
  11.   
  12.     TriangleWindow window;  
  13.     window.setFormat(format);  
  14.     window.resize(640, 480);  
  15.     window.show();  
  16.   
  17.     return app.exec();  
  18. }  

另一种写法:

[cpp]  view plain  copy
  1. #ifndef TRIANGLEWINDOW_H  
  2. #define TRIANGLEWINDOW_H  
  3.   
  4. #include <QWindow>  
  5.   
  6. class QOpenGLContext;  
  7.   
  8. class Renderer : public QObject  
  9. {  
  10.     Q_OBJECT  
  11. public:  
  12.     explicit Renderer(const QSurfaceFormat &format, Renderer *share = 0, QScreen *screen = 0);  
  13.     QSurfaceFormat format() const { return m_format; }  
  14.   
  15. public slots:  
  16.     void render(QSurface *surface, const QColor &color, const QSize &viewSize);  
  17.   
  18. private:  
  19.     void initialize();  
  20.   
  21.     bool m_initialized;  
  22.     QSurfaceFormat m_format;  
  23.     QOpenGLContext *m_context;  
  24. };  
  25.   
  26. class TriangleWindow : public QWindow  
  27. {  
  28.     Q_OBJECT  
  29. public:  
  30.     explicit TriangleWindow(const QSharedPointer<Renderer> &renderer);  
  31.       
  32. signals:  
  33.     void needRender(QSurface *surface, const QColor &color, const QSize &viewSize);  
  34.   
  35. private slots:  
  36.     void render();  
  37.   
  38. protected:  
  39.     void exposeEvent(QExposeEvent *);  
  40.   
  41. private:  
  42.     const QSharedPointer<Renderer> m_renderer;  
  43. };  
  44.   
  45. #endif // TRIANGLEWINDOW_H  

实现文件:

[cpp]  view plain  copy
  1. #include "trianglewindow.h"  
  2.   
  3. #include <QOpenGLContext>  
  4.   
  5. Renderer::Renderer(const QSurfaceFormat &format, Renderer *share, QScreen *screen)  
  6.     : m_initialized(false)  
  7.     , m_format(format)  
  8. {  
  9.     m_context = new QOpenGLContext(this);  
  10.     if (screen)  
  11.         m_context->setScreen(screen);  
  12.     m_context->setFormat(format);  
  13.     if (share)  
  14.         m_context->setShareContext(share->m_context);  
  15.     m_context->create();  
  16. }  
  17.   
  18. TriangleWindow::TriangleWindow(const QSharedPointer<Renderer> &renderer)  
  19.     : m_renderer(renderer)  
  20. {  
  21.     setSurfaceType(QWindow::OpenGLSurface);  
  22.     setFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);  
  23.   
  24.     setGeometry(QRect(10, 10, 640, 480));  
  25.   
  26.     setFormat(renderer->format());  
  27.   
  28.     create();  
  29.   
  30.     connect(this, SIGNAL(needRender(QSurface *, const QColor &, const QSize &)),  
  31.             renderer.data(), SLOT(render(QSurface *, const QColor &, const QSize &)));  
  32.   
  33. }  
  34.   
  35. void TriangleWindow::exposeEvent(QExposeEvent *)  
  36. {  
  37.     render();  
  38. }  
  39.   
  40. void TriangleWindow::render()  
  41. {  
  42.     if (isExposed())  
  43.         emit needRender(this, QColor(255, 0, 0), size());  
  44. }  
  45.   
  46. void Renderer::render(QSurface *surface, const QColor &color, const QSize &viewSize)  
  47. {  
  48.     if (!m_context->makeCurrent(surface))  
  49.         return;  
  50.   
  51.     if (!m_initialized) {  
  52.         initialize();  
  53.         m_initialized = true;  
  54.     }  
  55.   
  56.     glViewport(0, 0, viewSize.width(), viewSize.height());  
  57.   
  58.     glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());  
  59.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
  60.   
  61.     m_context->swapBuffers(surface);  
  62.   
  63. }  
  64.   
  65. void Renderer::initialize()  
  66. {  
  67.     glClearColor(0.1f, 0.1f, 0.2f, 1.0f);  
  68. }  

main方法:

[cpp]  view plain  copy
  1. #include "trianglewindow.h"  
  2.   
  3. #include <QGuiApplication>  
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     QGuiApplication app(argc, argv);  
  8.   
  9.     QSurfaceFormat format;  
  10.     format.setDepthBufferSize(16);  
  11.     format.setSamples(4);  
  12.   
  13.     QSharedPointer<Renderer> renderer(new Renderer(format));  
  14.     TriangleWindow *window = new TriangleWindow(renderer);  
  15.     window->resize(640, 480);  
  16.     window->setVisible(true);  
  17.   
  18.     return app.exec();  
  19. }  

在Qt5,推荐使用QOpenGL*系列的类。


from: http://blog.youkuaiyun.com/fuyajun01/article/details/9246231


<think>我们正在比较Qt5Qt6的语法差异。根据提供的引用,我们可以总结出一些关键点。注意,Qt6相对于Qt5进行了一些重大的更改,包括模块的添加、删除和重写,以及一些API的变更。以下是一些主要的语法差异: 1. **模块和头文件的变化**: - Qt6中,一些模块被移除或合并。例如,`QtWidgets`模块现在必须显式包含(在Qt5中,有时可以省略,但Qt6更严格)。 - 一些头文件被重组织。例如,在Qt6中,`QDesktopWidget`被移到`QtGui`模块,而不再在`QtWidgets`中。 2. **字符串处理**: - Qt6中,`QString`类进行了重构,移除了许多过时的方法。例如,`QString::split`的返回值类型从`QStringList`变成了`QList<QStringView>`(但实际使用中,我们通常还是用`QStringList`,因为提供了兼容的API)。不过,一些方法如`QString::mid`、`QString::left`等返回类型变为`QStringView`,这意味着它们不进行深拷贝,但要注意生命周期。 3. **图形视图框架**: - 在Qt6中,与OpenGL相关的类被移除,并移到了单独的模块(如`QtOpenGL`或`QtShaderTools`)。因此,如果项目中使用到`QOpenGL*`系列类,需要包含相应的模块,并在项目文件中添加依赖。 4. **多媒体模块**: - 引用[4]提到,Qt6的`QCamera`等多媒体类有重大变化。在Qt5中,使用`QCamera`、`QCameraViewfinder`和`QCameraImageCapture`来操作摄像头。在Qt6中,这些类被重构,引入了的设备发现机制和API。 5. **网络模块**: - Qt6中,`QNetworkAccessManager`的API有所变化,例如,`QNetworkReply`的错误处理信号现在使用`QNetworkReply::errorOccurred`而不是`QNetworkReply::error`(后者在Qt5中被标记为过时,在Qt6中移除)。 6. **信号和槽的语法**: - 在Qt5中,我们通常使用`SIGNAL()`和`SLOT()`宏(老式连接)或者使用函数指针(式连接)。在Qt6中,老式连接已经被完全移除,必须使用式连接。另外,Qt6引入了的信号和槽语法,允许连接任意函数(包括lambda表达式)而无需使用`Q_OBJECT`宏(但仅适用于式连接)。 7. **属性系统**: - Qt6中,属性系统进行了扩展,支持更多的元类型。同时,`Q_PROPERTY`现在支持绑定属性和JavaScript交互的改进。 8. **容器类**: - Qt6中,容器类(如`QList`、`QVector`)进行了重构。`QVector`在Qt6中被移除,统一使用`QList`(但`QList`在Qt6中的实现与Qt5的`QVector`类似,即连续内存分配)。 9. **枚举类型**: - Qt6中,许多枚举类型被改为枚举类(enum class),这导致它们必须使用作用域运算符(`::`)来访问,并且不能隐式转换为整数。例如,在Qt5中,`Qt::AlignLeft`可以直接使用,在Qt6中,它仍然是`Qt::AlignLeft`,但如果是枚举类,则必须注意作用域。 10. **C++标准要求**: - Qt6要求使用C++17或更高版本,而Qt5可以在较低的标准(如C++11)下编译。因此,在Qt6中,可以使用C++17的特性。 下面通过一些代码示例来具体说明: **示例1:字符串处理(Qt5 vs Qt6)** 在Qt5中,我们可以这样写: ```cpp QString str = "Hello, World"; QStringList parts = str.split(","); ``` 在Qt6中,同样的代码仍然有效,但要注意`split`返回的是`QList<QStringView>`,但会自动转换为`QStringList`(因为`QStringList`是`QList<QString>`的别名)。然而,如果使用`QStringView`,则: ```cpp QString str = "Hello, World"; QList<QStringView> parts = QStringView(str).split(u","); ``` **示例2:信号和槽的连接(Qt5 vs Qt6)** Qt5中老式连接(不推荐,但在Qt6中已移除): ```cpp connect(button, SIGNAL(clicked()), this, SLOT(handleButton())); ``` Qt5/Qt6式连接: ```cpp connect(button, &QPushButton::clicked, this, &MyClass::handleButton); ``` Qt6中,还可以使用重载的解决方式(使用函数指针)或者使用`QOverload`(如果需要连接重载信号): ```cpp // 假设有一个重载的信号:void mySignal(int); void mySignal(const QString &); connect(sender, QOverload<int>::of(&MySender::mySignal), receiver, &MyReceiver::handleInt); // 在Qt5.7及以上,可以使用以下写法,但在Qt6中同样适用 connect(sender, static_cast<void (MySender::*)(int)>(&MySender::mySignal), receiver, ...); ``` **示例3:枚举类(Qt6)** 在Qt6中,例如`QFile`的枚举`Permission`现在被改为枚举类,所以: ```cpp // Qt5 file.setPermissions(QFile::ReadOwner | QFile::WriteOwner); // Qt6 file.setPermissions(QFile::Permission::ReadOwner | QFile::Permission::WriteOwner); ``` **示例4:多媒体(引用[4])** Qt5中的摄像头使用: ```cpp // Qt5 #include <QCamera> #include <QCameraViewfinder> #include <QCameraImageCapture> QCamera *camera = new QCamera; QCameraViewfinder *viewfinder = new QCameraViewfinder; camera->setViewfinder(viewfinder); camera->start(); ``` 在Qt6中,多媒体模块被重写,使用的API: ```cpp // Qt6 #include <QMediaCaptureSession> #include <QCamera> #include <QVideoWidget> QCamera *camera = new QCamera; QVideoWidget *videoWidget = new QVideoWidget; QMediaCaptureSession *captureSession = new QMediaCaptureSession; captureSession->setCamera(camera); captureSession->setVideoOutput(videoWidget); videoWidget->show(); camera->start(); ``` **总结**: Qt6相对于Qt5在语法上的主要变化包括:模块重组、头文件路径变化、字符串处理优化、信号槽连接强制使用式、枚举改为枚举类、容器类优化以及要求C++17标准等。在迁移项目时,需要特别注意这些变化,并逐步修改代码以适应Qt6。 最后,建议在迁移前阅读Qt官方文档的[移植指南](https://doc.qt.io/qt-6/portingguide.html)。 --- ### §§相关问题§§ 1. 如何将Qt5项目迁移到Qt6? 2. Qt6中哪些模块被移除了?如何替代? 3. 在Qt6中如何处理OpenGL相关代码? 4. Qt6中信号和槽的特性有哪些? 5. Qt6对C++标准的要求是什么?</think>### Qt5Qt6 语法差异对比 #### 一、核心语法变化 1. **模块重构** - **Qt5**:使用 `QtWidgets` 作为 GUI 核心模块 ```cpp #include <QtWidgets/QApplication> // Qt5 ``` - **Qt6**:引入模块化架构,必须显式声明模块[^1] ```cpp #include <QApplication> // Qt6 (需在.pro文件添加QT += widgets) ``` 2. **字符串处理** - **Qt5**:`QString::split()` 返回 `QStringList` ```cpp QStringList parts = str.split(","); // Qt5 ``` - **Qt6**:返回 `QList<QStringView>` 需转换[^1] ```cpp auto parts = str.split(","); // Qt6 QStringList list = QStringList(parts.cbegin(), parts.cend()); ``` 3. **容器类 API** - **Qt5**:`QVector` 作为主要连续容器 ```cpp QVector<int> vec = {1,2,3}; // Qt5 ``` - **Qt6**:统一使用 `QList` 替代 `QVector`[^2] ```cpp QList<int> list = {1,2,3}; // Qt6 ``` #### 二、多媒体模块差异 1. **摄像头 API 重写**[^4] ```cpp // Qt5 摄像头控制 QCamera *camera = new QCamera; QCameraViewfinder *viewfinder = new QCameraViewfinder; camera->setViewfinder(viewfinder); // Qt6 架构 QMediaCaptureSession session; QCamera camera; QVideoWidget widget; session.setCamera(&camera); session.setVideoOutput(&widget); ``` 2. **音频处理** - Qt5:`QAudioOutput` 直接控制设备 - Qt6:必须通过 `QMediaPlayer` 或 `QSoundEffect` #### 三、关键语法废弃项 | 功能 | Qt5 语法 | Qt6 替代方案 | |------------------|------------------------------|-------------------------------| | OpenGL 集成 | `QOpenGLWidget` | 需单独安装 `QtOpenGL` 模块[^2] | | 正则表达式 | `QRegExp` | `QRegularExpression` | | 物理像素获取 | `qApp->devicePixelRatio()` | `window()->devicePixelRatio()`| | 进程间通信 | `QDesktopServices::openUrl()`| `QProcess::startDetached()` | #### 四、迁移注意事项 1. **头文件包含** ```cpp // Qt5 兼容方式 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include <QtWidgets/QHeaderView> #else #include <QHeaderView> #endif ``` 2. **枚举作用域变化** ```cpp // Qt5 widget->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint); // Qt6 (枚举类作用域) widget->setWindowFlags(Qt::WindowType::Dialog | Qt::WindowType::CustomizeWindowHint); ``` 3. **信号连接语法** ```cpp // Qt5/Qt6通用语法 connect(button, &QPushButton::clicked, [=](){ qDebug() << "Button clicked"; }); // Qt5旧语法(在Qt6中被废弃) connect(button, SIGNAL(clicked()), this, SLOT(onClick())); ``` > **迁移建议**: > 1. 使用 `QT_VERSION_CHECK` 宏实现跨版本兼容 > 2. 优先采用的信号槽语法 > 3. 多媒体模块需完全重写[^4] > 4. 图形相关功能需链接 `QtOpenGL` 模块[^2] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值