Qt+OpenGL联合编程(1)

     最近发现了Qt在界面设计方面的优良性能,遂决定开始学习,奈何自己出身计算机图形学专业,如能将它们结合起来自是最好啦。

     参考Nokia Developer网站上关于《如何在Qt中使用OpenGl》的文章,记录下自己的实际使用过程。http://www.developer.nokia.com/Community/Wiki/%E5%A6%82%E4%BD%95%E5%9C%A8Qt%E4%B8%AD%E4%BD%BF%E7%94%A8OpenGL

同时也参考了tornadomeet的《OpenGL_Qt学习笔记之_01(创建一个OpenGL窗口)》http://www.cnblogs.com/tornadomeet/archive/2012/08/22/2651574.html

     OpenGL(Open Graphics Library)我就不多说了,它定义了一个跨编程语言、跨平台的编程接口的规格,用于生成二维、三维图像。Qt主要通过QGLWidget这个类来实现,将opengl的函数和Qt的界面结合。所以一般开发opengl,同时要用到Qt的界面时,这些类都可以从QGLWidget继承过来。

 


开发环境:windows 7+Qt 4.7.3+QtCreater 2.5.0

1.选择工程类型时,选择Qt Gui Application

2.进入Class Information界面时,此时基类可以选择QMainWindow或者QWidget,因为后面还是要进行修改,所以这里差别不大。但是没有试过QDialog,不知道情况怎么样。

之后的实验来自Nokia Developer


OpenGLQt.pro

为了使用QtOpenGL Module, 我们必须设.pro文件

QT       += core gui\
             opengl  \\这里新加了一个opengl选项

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = BBSS_System_QT
TEMPLATE = app


SOURCES += main.cpp\
        openglqt.cpp

HEADERS  += openglqt.h

FORMS    += openglqt.ui

openglqt.h

ps: OpenGLQt类继承于QGLWidget,主要是重写了3个函数,initializeGL();paintGL();resizeGL();3个函数都是QGLWidget内部的虚函数。

#ifndef OPENGLQT_H
#define OPENGLQT_H

#include <QWidget>
#include <QtOpenGL>

namespace Ui {
class OpenGLQt;
}

class OpenGLQt : public QGLWidget
{
    Q_OBJECT
    
public:
    explicit OpenGLQt(QWidget *parent = 0);
    ~OpenGLQt();
    
private:
    Ui::OpenGLQt *ui;

protected:
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);

private:
void draw();
int faceAtPosition(const QPoint &pos);
GLfloat rotationX;
GLfloat rotationY;
GLfloat rotationZ;
QColor faceColors[4];
QPoint lastPos;
void Spin(int xAngle, int yAngle, int zAngle);
 private slots:
 void Rotate();
};

#endif // OPENGLQT_H

openglqt.cpp

#include "openglqt.h"
#include "ui_openglqt.h"

OpenGLQt::OpenGLQt(QWidget *parent) :
    QGLWidget(parent),
    ui(new Ui::OpenGLQt)
{
    //QGLWidget::setFormat() to specify the OpenGL display context
       setFormat(QGLFormat(QGL::DoubleBuffer | QGL::DepthBuffer));
       rotationX = -21.0;
       rotationY = -57.0;
       rotationZ = 0.0;

       // Note: Square faces are set with static color and are cannot be changed during runtime
        // set the color of the faces of Tetrahedron
       faceColors[0] = Qt::red;
       faceColors[1] = Qt::green;
       faceColors[2] = Qt::blue;
       faceColors[3] = Qt::yellow;

       initializeGL();
       resizeGL(51,51);
       paintGL();

       //timer to spin the object
       QTimer *timer = new QTimer(this);
       connect(timer, SIGNAL(timeout()), this, SLOT(Rotate()));
       timer->start(20);
}

OpenGLQt::~OpenGLQt()
{
    delete ui;
}

void OpenGLQt::initializeGL()
{
qglClearColor(Qt::black);
glShadeModel(GL_FLAT);   //设置阴影平滑模式
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}

void OpenGLQt::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat x = GLfloat(width) / height;
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
}

void OpenGLQt::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
}

void OpenGLQt::draw()
{

    //change the value if don't want to spin automatically and want to check the mouse event
   // glRotatef(rotationX/16.0f, 1.0, 0.0, 0.0); to glRotatef(rotationX, 1.0, 0.0, 0.0);
   // glRotatef(rotationY/16.0f, 0.0, 1.0, 0.0); to glRotatef(rotationY, 0.0, 1.0, 0.0);
    //glRotatef(rotationZ/16.0f, 0.0, 0.0, 1.0); to glRotatef(rotationZ, 0.0, 0.0, 1.0);


    // Draw Tetrahedron
    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(rotationX/16.0f, 1.0, 0.0, 0.0);
    glRotatef(rotationY/16.0f, 0.0, 1.0, 0.0);
    glRotatef(rotationZ/16.0f, 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 OpenGLQt::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
}

void OpenGLQt::mouseMoveEvent(QMouseEvent *event)
{
GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
if (event->buttons() & Qt::LeftButton) {
rotationX += 180 * dy;
rotationY += 180 * dx;
updateGL();
}
else if (event->buttons() & Qt::RightButton)
{
rotationX += 180 * dy;
rotationZ += 180 * dx;
updateGL();
}
lastPos = event->pos();
}

void OpenGLQt::mouseDoubleClickEvent(QMouseEvent *event)
{
int face = faceAtPosition(event->pos());
if (face != -1) {
QColor color = QColorDialog::getColor(faceColors[face], this);
if (color.isValid()) {
faceColors[face] = color;
updateGL();
}
}
}

int OpenGLQt::faceAtPosition(const QPoint &pos)
{
const int MaxSize = 512;
GLuint buffer[MaxSize];
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glSelectBuffer(MaxSize, buffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix(GLdouble(pos.x()), GLdouble(viewport[3] - pos.y()),
5.0, 5.0, viewport);
GLfloat x = GLfloat(width()) / height();
glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
draw();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
if (!glRenderMode(GL_RENDER))
return -1;
return buffer[3];
}

void OpenGLQt::Rotate()
{
    //QMessageBox::about(this,"Hello","world");
      this->Spin(+2 * 16, +2 * 16, -1 * 16);
}
void OpenGLQt::Spin(int xAngle, int yAngle, int zAngle)
{
    rotationX += xAngle;
    rotationY += yAngle;
    rotationZ += zAngle;
    updateGL();
}
  1. 在构造函数中调用setFormat 设置OPENGL的显示方式.
  2. 函数initializeGL()在paintGL()之前调用,且只调用一次,在这里可以设置OpenGL的显示内容,定义显示列表或者其他初始化操作。其中qglClearColor()是QGLWidget的函数,其他函数都是OpenGL标准函数。如果全部遵循OpenGL库,可以调用RGBA格式的glClearColor()函数和颜色索引函数glClearIndex()。
  3. PaintGL() 函数将在任何需要重绘的时候调用,真正是在draw 函数中执行绘图操作
  4. 在draw函数中我们绘制四面体
  5. Spin() 函数用于旋转四面体到特定的角度

 

main.cpp

#include <QApplication>
#include "openglqt.h"
#include <iostream>
#include <QtOpenGL>
using namespace std;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (!QGLFormat::hasOpenGL()) {
    cerr << "This system has no OpenGL support" << endl;
    return 1;
    }
    OpenGLQt openglqt;
    openglqt.setWindowTitle(QObject::tr("OpenGL Qt"));
    openglqt.resize(300, 300);
    openglqt.show();
    return a.exec();
}

运行结果

 


编译和运行能够正常,可是当关闭的时候就出现错误提示:"

ASSERT: "group->context() == q_ptr" in file .\qgl.cpp, line 1657

上网搜了一下这个问题,在http://blog.sina.com.cn/s/blog_404dab3b0101f2e5.html中找到了解决方案:

原来是现在的版本不能在构造函数里设置:

setFormat(QGLFormat(QGL::DoubleBuffer|QGL::DepthBuffer))

只要这样设置就会在关闭程序的时候出错。所以只有在构造函数的初始化列表里传递参数设置,比如:

OpenGLQt::OpenGLQt(QWidget *parent) :
    QGLWidget(QGLFormat(QGL::DoubleBuffer|QGL::DepthBuffer),parent),
    ui(new Ui::OpenGLQt){
......
}

 这样果然在关闭程序的时候不会再抛出错误了。

posted @ 2013-07-09 16:00  BambooQQ  阅读(8592)  评论(0编辑  收藏  举报