OpenGL是绘制三维图形的标准API。Qt应用程序可以使用QtOpenGL模块绘制三维图形,该模块依赖于系统的OpenGL库。Qt OpenGL模块提供QGLWidget类,可以通过对它子类化,并使用OpenGL命令开发出自己的窗口部件。对许多三维应用程序来说,这就足够了。

这节假设大家都已经学过OpenGL,这样我们就无后顾之忧了。

在Qt中绘制OpenGL通常需要做以下工作:1)、必须子类化QGLWidget;2)、实现几个虚函数:void initiallizeGL()

void resizeGL(), void paintGL(), 这些都是在QGLWidget中实现的,还有一些和用户交互的虚函数,诸如void mouseMoveEvent()之类的,想必大家都比较熟了,这些虚函数是在Widget中实现的。

下面我们介绍一个例子。先给出该程序的效果:

菜单栏里的第一项可以完成一个自定义大小的抓图,即由用户自己决定抓图的大小,抓图会显示在右侧的方框里,注意这里只能设置图形的大小小雨当前图形的尺寸, 如果大于当前图形尺寸,则钳位到当前图形尺寸。效果 看起来应该是这样:

菜单栏第二项也是一个抓图功能,它返回一个当前图形尺寸的图形,并填充到右侧。

第三项即清除右侧图形。

这个代码由以下部件构成:

一个QMainWindow,我们通过子类化这个类来完成自己想要的一些功能。

一个QWidget,我们把它作为中央窗口,在其上添加自己想要的一些子部件。

两个QScrollBar,用来盛载一个QGLWidget和一个QLabel。

一个QGLWidget,我们通过子类化它并把它加进一个QScrollBar来实现三维绘图,即上图所示的左边窗口。

一个QLabel,同样,我们把这个QLabel加进一个QScrollBar来接收抓图后的显示效果。

三个QSlider,我们通过这三个滑动条控制所绘制的四面体沿x,y,z轴转动,同样鼠标拖动这个四面体也可以改变滑动条的值。

以上是整个程序的框架。

以下是代码的实现部分。

MainWindow 类定义了我们整个程序的框架:

//mainwindow.h

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include

class QAction;

class QLabel;

class QMenu;

class QSlider;

class QScrollArea;

class GLWidget;

class MainWindow : public QMainWindow

{

Q_OBJECT

public:

MainWindow(QWidget *parent = 0);

~MainWindow();

private slots:

void renderIntoPixmap();

void grabFrameBuffer();

void clearPixmap();

void about();

private:

void createMenus();

void createActions();

QSlider *createSlider(const char *changedSignal, const char *setterSlot);

void setPixmap(const QPixmap &pixmap);

QSize getSize();

QWidget *centralWidget;

QScrollArea *glWidgetArea;

QScrollArea *pixmapLabelArea;

GLWidget *glWidget;

QLabel *pixmapLabel;

QSlider *xSlider;

QSlider *ySlider;

QSlider *zSlider;

QMenu *fileMenu;

QMenu *helpMenu;

QAction *renderIntoPixmapAction;

QAction *grabFrameBufferAction;

QAction *clearPixmapAction;

QAction *exitAction;

QAction *aboutAction;

QAction *aboutQtAction;

};

#endif // MAINWINDOW_H

以下是程序的实现部分:

//mainwindow.cpp

#include

#include

#include

#include

#include

#include

#include

#include

#include "mainwindow.h"

#include "glwidget.h"

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent)

{

centralWidget = new QWidget;

setCentralWidget(centralWidget);

glWidget = new GLWidget;

pixmapLabel = new QLabel;

glWidgetArea = new QScrollArea;

glWidgetArea->setWidget(glWidget);

//glWidgetArea->viewport()->setBackgroundRole(QPalette::Dark);

glWidgetArea->setWidgetResizable(true);

glWidgetArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

glWidgetArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

glWidgetArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

glWidgetArea->setMinimumSize(50, 50);

pixmapLabelArea = new QScrollArea;

pixmapLabelArea->setWidget(pixmapLabel);

pixmapLabelArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

pixmapLabelArea->setMinimumSize(50, 50);

//在构造一个QSlider时将QGLWidget的信号和槽传给这个函数的形参,这样就可以在QMainWindow中

//控制OpenGL的动作了,而让GLWidget类只完成绘图工作。

xSlider = createSlider(SIGNAL(xRotationChanged(int)),

SLOT(setXRotation(int)));

ySlider = createSlider(SIGNAL(yRotationChanged(int)),

SLOT(setYRotation(int)));

zSlider = createSlider(SIGNAL(zRotationChanged(int)),

SLOT(setZRotation(int)));

/*

xSlider = new QSlider(Qt::Horizontal);

ySlider = new QSlider(Qt::Horizontal);

zSlider = new QSlider(Qt::Horizontal);

*/

QGridLayout *centralLayout = new QGridLayout;

centralLayout->addWidget(glWidgetArea, 0, 0);

centralLayout->addWidget(pixmapLabelArea, 0, 1);

centralLayout->addWidget(xSlider, 1, 0, 1, 2);

centralLayout->addWidget(ySlider, 2, 0, 1, 2);

centralLayout->addWidget(zSlider, 3, 0, 1, 2);

centralWidget->setLayout(centralLayout);

createActions();

createMenus();

xSlider->setValue(15 * 16);

ySlider->setValue(345 * 16);

zSlider->setValue(0 * 16);

setWindowTitle(tr("Grabeer"));

resize(480, 360);

}

void MainWindow::setPixmap(const QPixmap &pixmap)

{

pixmapLabel->setPixmap(pixmap);

QSize size = pixmap.size();

if (size - QSize(1, 0) == pixmapLabelArea->maximumViewportSize())

size -= QSize(1, 0);

pixmapLabel->resize(size);

}

QSize MainWindow::getSize()

{

bool ok;

QString text = QInputDialog::getText(this, tr("Grabber"),

tr("Enter Pixmap Size:"),

QLineEdit::Normal,

tr("%1 x %2").arg(glWidget->width())

.arg(glWidget->height()),

&ok);

if (!ok)

return QSize();

QRegExp regExp(tr("([0-9]+) *x *([0-9]+)"));

if (regExp.exactMatch(text)) {

int width = regExp.cap(1).toInt();

int height = regExp.cap(2).toInt();

if (width > 0 && width < 2048 && height > 0 && height < 2048)

return QSize(width, height);

}

return glWidget->size();

}

void MainWindow::renderIntoPixmap()

{

QSize size = getSize();

if (size.isValid()) {

QPixmap pixmap = glWidget->renderPixmap(size.width(), size.height());

setPixmap(pixmap);

}

}

void MainWindow::grabFrameBuffer()

{

//QGLWidget有一个返回其帧缓冲区的QImage图片的函数

QImage image = glWidget->grabFrameBuffer();

//QPixmap的fromImage函数把一个QImage转换成QPixmap

setPixmap(QPixmap::fromImage(image));

}

void MainWindow::clearPixmap()

{

setPixmap(QPixmap()); //给它传一个空的对象

}

void MainWindow::about()

{

QMessageBox::about(this, tr("About Grabber"),

tr("The Grabber example demonstrates two approaches for "

"rendering OpenGL into a Qt pixmap."));

}

QSlider *MainWindow::createSlider(const char *changedSignal,

const char *setterSlot)

{

QSlider *slider = new QSlider(Qt::Horizontal);

slider->setRange(0, 16 * 360);

slider->setSingleStep(16);

slider->setPageStep(15 * 16);

slider->setTickInterval(15 * 16);

slider->setTickPosition(QSlider::TicksRight);

//这种经典的用法一定要小心,报错:glWidget的槽函数在传进来的时候已经被强制转换成SLOT了,

//所以setterSlot不用SLOT修饰;同样,changedSignal也不能再拿SIGNAL修饰

connect(slider, SIGNAL(valueChanged(int)), glWidget, setterSlot);

connect(glWidget, changedSignal, slider, SLOT(setValue(int)));

return slider;

}

void MainWindow::createActions()

{

renderIntoPixmapAction = new QAction(tr("&Render into Pixmap..."), this);

renderIntoPixmapAction->setShortcut(tr("Ctrl+R"));

renderIntoPixmapAction->setToolTip(tr("yes, triggerd it"));

connect(renderIntoPixmapAction, SIGNAL(triggered()),

this, SLOT(renderIntoPixmap()));

grabFrameBufferAction = new QAction(tr("&Grab Frame Buffer"), this);

grabFrameBufferAction->setShortcut(tr("Ctrl+G"));

connect(grabFrameBufferAction, SIGNAL(triggered()),

this, SLOT(grabFrameBuffer()));

clearPixmapAction = new QAction(tr("&Clear Pixmap"), this);

clearPixmapAction->setShortcut(tr("Ctrl+L"));

connect(clearPixmapAction, SIGNAL(triggered()), this, SLOT(clearPixmap()));

exitAction = new QAction(tr("E&xit"), this);

exitAction->setShortcuts(QKeySequence::Quit);

connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));

aboutAction = new QAction(tr("&About"), this);

connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));

aboutQtAction = new QAction(tr("About &Qt"), this);

connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

}

void MainWindow::createMenus()

{

fileMenu = menuBar()->addMenu(tr("&File"));

fileMenu->addAction(renderIntoPixmapAction);

fileMenu->addAction(grabFrameBufferAction);

fileMenu->addAction(clearPixmapAction);

fileMenu->addSeparator();

fileMenu->addAction(exitAction);

helpMenu = menuBar()->addMenu(tr("&Help"));

helpMenu->addAction(aboutAction);

helpMenu->addAction(aboutQtAction);

}

MainWindow::~MainWindow()

{

}

GLWidget类是整个绘图的部分,在这部分虽然用了一点Qt的东西,但我们不是非要这样使用,我们可以用整个纯净的OpengGL库来完成我们的绘制。

//glwidget.h

#ifndef GLWIDGET_H

#define GLWIDGET_H

#include

class GLWidget : public QGLWidget

{

Q_OBJECT

public:

explicit GLWidget(QWidget *parent = 0);

int xRotation() const { return xRot; }

int yRotation() const { return yRot; }

int zRotation() const { return zRot; }

signals:

void xRotationChanged(int angle);

void yRotationChanged(int angle);

void zRotationChanged(int angle);

public slots:

void setXRotation(int angle);

void setYRotation(int angle);

void setZRotation(int angle);

protected:

void initializeGL();

void paintGL();

void resizeGL(int w, int h);

void mousePressEvent(QMouseEvent *event);

void mouseMoveEvent(QMouseEvent *event);

private slots:

void alwaysRotate();

void drawTriangle();

private:

void normalizeAngle(int *angle);

int xRot;

int yRot;

int zRot;

QColor faceColors[4];

QPoint lastPos;

};

#endif // GLWIDGET_H

以下是代码实现部分:

//glwidget.cpp

#include

#include

#include

#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent) :

QGLWidget(parent)

{

xRot = 0;

yRot = 0;

zRot = 0;

faceColors[0] = Qt::red;

faceColors[1] = Qt::green;

faceColors[2] = Qt::blue;

faceColors[3] = Qt::yellow;

QTimer *timer = new QTimer(this);

connect(timer, SIGNAL(timeout()), this, SLOT(alwaysRotate()));

timer->start(70);

}

void GLWidget::initializeGL()

{

glClearColor(0.0, 0.2, 0.3, 1.0);

glShadeModel(GL_SMOOTH);

glEnable(GL_DEPTH);

}

void GLWidget::paintGL()

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();

drawTriangle();

glPopMatrix();

}

void GLWidget::resizeGL(int w, int h)

{

int side = qMin(w, h);

glViewport((width() - side) / 2, (height() - side) / 2, side, side);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glFrustum(-1.2, 1.2, -1.2, 1.2, 5.0, 60.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glTranslatef(0.0, 0.0, -40.0);

}

void GLWidget::mousePressEvent(QMouseEvent *event)

{

lastPos = event->pos();

}

void GLWidget::mouseMoveEvent(QMouseEvent *event)

{

int dx = event->x() - lastPos.x();

int dy = event->y() - lastPos.y();

if (event->buttons() & Qt::LeftButton) {

(xRot + 4 * dx);

setYRotation(yRot + 4 * dy);

} else if (event->buttons() & Qt::RightButton) {

(xRot + 4 * dy);

setZRotation(zRot + 4 * dx);

}

lastPos = event->pos();

}

void GLWidget::drawTriangle()

{

static const GLfloat P1[3] = { 0.0, -1.0, +2.0 };

static const GLfloat P2[3] = { +1.73205081, -1.0, -1.0 };

static const GLfloat P3[3] = { -1.73205081, -1.0, -1.0 };

static const GLfloat P4[3] = { 0.0, +2.0, 0.0 };

static const GLfloat * const coords[4][3] = {

{ P1, P2, P3 }, { P1, P3, P4 }, { P1, P4, P2 }, { P2, P4, P3 }

};

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glTranslatef(0.0, 0.0, -10.0);

glRotatef(xRot, 1.0, 0.0, 0.0);

glRotatef(yRot, 0.0, 1.0, 0.0);

glRotatef(zRot, 0.0, 0.0, 1.0);

for (int i = 0; i != 4; ++i) {

//glLoadName(i);

glBegin(GL_TRIANGLES);

qglColor(faceColors[i]);

for (int j = 0; j < 3; ++j) {

glVertex3f(coords[i][j][0], coords[i][j][1],

coords[i][j][2]);

}

glEnd();

}

}

void GLWidget::normalizeAngle(int *angle)

{

while (*angle < 0)

angle += 360 * 16;

while (*angle > 360 *16)

angle -= 360 *16;

}

void GLWidget::setXRotation(int angle)

{

normalizeAngle(&angle);

if ( angle != xRot ) {

xRot = angle;

emit xRotationChanged(angle);

updateGL();

}

}

void GLWidget::setYRotation(int angle)

{

normalizeAngle(&angle);

if ( angle != yRot ) {

yRot = angle;

emit yRotationChanged(angle);

updateGL();

}

}

void GLWidget::setZRotation(int angle)

{

normalizeAngle(&angle);

if ( angle != zRot ) {

zRot = angle;

emit zRotationChanged(angle);

updateGL();

}

}

void GLWidget::alwaysRotate()

{

zRot += 2;

emit zRotationChanged(zRot);

updateGL();

}

至此,我们就完成了整个应用程序的编写,继续努力。

opengl png图片 qt_Qt学习:三维绘图之OpenGL和Qt的结合(转)相关推荐

  1. opengl png图片 qt_QT中使用OpenGL绘图

    在之前说道过VS2010中配合OpenGL绘图的问题,这回是想要说说在QT中使用OpenGL,其实两者并无太大区别,因为都是基于C++语言的. 主要是想简要介绍下OpenGL在QT中的使用方法跟一些错 ...

  2. opengl png图片 qt_Qt资源文件的格式,并用CMake添加Qt资源文件

    目录 ......QRC文件的写法用CMake添加Qt资源文件添加QRC文件的函数步骤CPP中使用QRC文件使用QRC文件实例程序结果QRC文件CMakeLists.txt文件Dialog.h文件Di ...

  3. opengl png图片 qt_Qt翻页效果实现(四):OpenGL图像渲染

    OpenGL贴图 OpenGL里面的图像渲染,是通过将图片映射成纹理,然后通过顶点坐标和对应的纹理坐标映射到物体表面. 顶点坐标 这里我们只有三个屏平面,在Qt翻页效果实现(二)文章中各点的坐标,在O ...

  4. opengl三维模型显示界面 qt_Qt OpenGL三维绘图

    OpenGL是为三维绘图提供的标准应用编程接口. OpenGL处理的仅仅是三维绘图方面,而很少或是根本不提供图形用户界面编程方面的支持.OpenGL*应用程序的用户界面必须由其它工具包创建,比如在X平 ...

  5. Python Qt(十三)PyQtDataVisualization三维绘图

    PyQtDataVisualization三维绘图 Data Visualization是Qt中的一个三维数据可视化模块,可以绘制三维柱状图.三维散点图.三维曲面图等.Data Visualizati ...

  6. MATLAB学习笔记——二维和三维绘图

    MATLAB学习笔记--二维和三维绘图 近期练习matlab的二维和三维绘图,整理一下,以防忘记. 文章目录 MATLAB学习笔记--二维和三维绘图 一.二维绘图 1.plot命令 2.fplot 命 ...

  7. MFC+OpenGL三维绘图(一)——简单绘图平台的搭建与实现图像的旋转、缩放

    声明:本文章为小白本人第一次创作,文章可能会有诸多不足,希望大家批评指正! VS2013下载:https://pan.baidu.com/s/1Y7TuZlLaGsbj2KCZV_uckw OpenG ...

  8. matlab 进阶绘图:图片保存,极坐标绘图,函数绘图,等高线地图,三维条形图,三维散点图,gif 绘图

    本文所包含的绘图方式: 极坐标绘图,函数绘图,等高线地图,三维条形图,三维散点图,gif 绘图 1 常用命令 hold on; % 持续绘图 hold off; 1.1 标注 xlabel(''); ...

  9. matlab 三维 作图 坐标轴_MATLAB学习——MATLAB中的三维绘图指令

    2 基本XYZ立体绘图命令 mesh和plot是三度空间立体绘图的基本命令,mesh可画出立体网状图,plot则可画出立体曲面图,两者产生的图形都会依高度而有不同颜色.下列命令可画出由函数 形成的立体 ...

最新文章

  1. 活用"端口碰撞技术"---远程管理的好方式
  2. 您的请求参数与订单信息不一致_长春各学校信息审核结果出炉!这些情况不符合“两个一致”...
  3. 解决“element表单验证输入的数字检测出来是string”的问题
  4. 用Flash创建一个类似Nano War游戏的教程
  5. 转自知乎大神----JS 的 new 到底是干什么的?
  6. boost::math::interpolators::cardinal_quadratic_b_spline用法的测试程序
  7. 块元素与行内元素转化(display属性)
  8. node mysql安装目录_nodejs 指定全局安装路径和缓存路径
  9. 第二次作业 讲解及展示
  10. python有理数_Python中的as_integer_ratio()用于减少给定有理数的分数
  11. tmpfs——Linux的一种虚拟内存文件系统
  12. WPF之Manipulation
  13. 微软亚洲研究院20周年庆典:纳德拉致敬、沈向洋展望
  14. 请大家慎用联想笔记本的NOVO功能
  15. [译]Java 设计模式之组合
  16. c语言免杀程序源码,ghost源码免杀教程 步
  17. 永远跳票的 永远的毁灭公爵
  18. 生物医学基础--人体阻抗模型
  19. C# Abp框架入门系列文章(一)
  20. 仅仅CSS就实现了轮播图----利用关键帧动画实现轮播图效果

热门文章

  1. arctanx麦克劳林公式推导过程_实用反三角函数运算公式
  2. ROG 冰刃 3 枪神 2 Plus 第二时间上手体验
  3. php限制一个函数在几分钟内不被调用_PHP - 无法在双引号内调用函数
  4. SonrLint常见解决方案
  5. 倒计时第3天,Google Summer of Code报名即将截止(Casbin社区还有空缺名额)
  6. 假设有一段英文,其中有单词中间的字母i误写为I,请编写程序进行矫正。
  7. 商用车市场「跌跌不休」,主动安全「让位」智能驾驶?
  8. android中注册的账号密码储存在,android SharedPreferences实现用户的注册和保存账号密码...
  9. 【图文详解】HBase 的数据模型与架构原理详解
  10. OpenGL环境下PLY三维模型的读入与显示