结果预览:
一.代码5个文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//glwidget.h #ifndef GLWIDGET_H #define GLWIDGET_H #include <QGLWidget> 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; QColor qtGreen, qtPurple; }; #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//glwidget.cpp #include <QtGui> #include <QtOpenGL> #include<math.h> #include"glwidget.h" #ifndef GL_MULTISAMPLE #define GL_MULTISAMPLE 0x809D #endif 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; qtGreen = QColor::fromCmykF(0.40, 0.0, 1.0, 0.0); qtPurple = QColor::fromCmykF(0.39, 0.39, 0.0, 0.0); QTimer *timer = new QTimer(this); connect(timer , SIGNAL(timeout()), this,SLOT(alwaysRotate())); timer->start(70); } void GLWidget::initializeGL() { qglClearColor(qtPurple.dark()); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH); glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); glEnable(GL_CULL_FACE); } 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) { setYRotation(yRot + 4*dy); } else if (event->buttons()&Qt::RightButton) { 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.73, -1.0, -1.0 }; static const GLfloat P3[3] = { -1.73, -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(); glTranslated( 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) { 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 +=12; if (zRot>16*360) zRot = 0; emit zRotationChanged(zRot); updateGL(); }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> 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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//mainwindow.cpp #include <QtOpenGL> #include <QAction> #include <QLabel> #include <QMenu> #include <QSlider> #include <QScrollArea> #include <QMenuBar> #include <QApplication> #include "mainwindow.h" #include "glwidget.h" #include <time.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) { //截图到磁盘 time_t curTime = time(NULL); QString path1 = "E:\",path2=".jpg"; QString path = QString::number(curTime, 10)+path2; pixmapLabel->setPixmap(pixmap); pixmap.save(path, 0, -1); 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 <b>Grabber</b> 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() { }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//main.cpp #include <QApplication> #include <QDesktopWidget> #include "mainwindow.h" #include "glwidget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; window.show(); //GLWidget widegt; //widegt.show(); return app.exec(); }
二.介绍
1.GLWidget控件类的实现
a.继承QGLWidget类
b.实例虚构OpenGL函数
protected: void initializeGL(); void paintGL(); void resizeGL(int w, int h); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
c.根据相关的功能添加函数和变量
d.c++语法两个,其一
int xRotation() const { return xRot; } int yRotation() const { return yRot; } int zRotation() const { return zRot; } //const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰. //常成员函数, 它不改变对象的成员变量. //也不能调用类中任何非const成员函数.
其二
explicit GLWidget(QWidget *parent = 0); //声明为explicit的构造函数不能在隐式转换中使用。
2.mainwindow类的实现.
a.实现鼠标拖动和slider保持一致.
举个简单的例子:
#include<QApplication> #include <QHBoxLayout> #include <QSlider> #include <QSpinBox> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget *window = new QWidget; window->setWindowTitle("Enter a Number"); QSpinBox *spinbox = new QSpinBox; QSlider *slider = new QSlider(Qt::Horizontal); spinbox->setRange(0, 130); slider->setRange(0, 130); QObject::connect(spinbox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); QObject::connect(slider,SIGNAL(valueChanged(int)), spinbox, SLOT(setValue(int))); spinbox->setValue(35); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(spinbox); layout->addWidget(slider); window->setLayout(layout); window->show(); return app.exec(); }
b.截图功能实现的工作原理..........