任务之余抽点时间出来写写博文,希望对新接触的朋友有帮助。今天在这里和大家一起学习一下实现图形
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 类定义了我们全部程序的框架:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45//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
以下是程序的实现部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163//mainwindow.cpp #include <QtOpenGL> #include <QAction> #include <QLabel> #include <QMenu> #include <QSlider> #include <QScrollArea> #include <QMenuBar> #include <QApplication> #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 <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() { }
盈盈月光,我掬一杯最清的;落落余辉,我拥一缕最暖的;灼灼红叶,我拾一片最热的;萋萋芳草,我摘一束最灿的;漫漫人生,我要采撷世间最重的———毅力。
GLWidget类是全部绘图的部分,在这部分虽然用了一点Qt的东西,但我们不是非要这样应用,我们可以用全部纯净的OpengGL库来实现我们的绘制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//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; }; #endif // GLWIDGET_H
以下是代码实现部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126//glwidget.cpp #include <QtGui> #include <QtOpenGL> #include <math.h> #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(); }
至此,我们就实现了全部应用程序的编写,继续努力。
文章结束给大家分享下程序员的一些笑话语录: 程序员打油诗
写字楼里写字间,写字间里程序员;
程序人员写程序,又拿程序换酒钱。
酒醒只在网上坐,酒醉还来网下眠;
酒醉酒醒日复日,网上网下年复年。
但愿老死电脑间,不愿鞠躬老板前;
奔驰宝马贵者趣,公交自行程序员。
别人笑我忒疯癫,我笑自己命太贱;
不见满街漂亮妹,哪个归得程序员。
最后
以上就是自由便当最近收集整理的关于实现图形Qt学习:三维绘图之OpenGL和Qt的结合的全部内容,更多相关实现图形Qt学习:三维绘图之OpenGL和Qt内容请搜索靠谱客的其他文章。
发表评论 取消回复