main.cpp
#include <QApplication> #include <iostream> #include "vowelcube.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); if (!QGLFormat::hasOpenGL()) { std::cerr << "This system has no OpenGL support" << std::endl; return 1; } VowelCube cube; cube.setWindowTitle(QObject::tr("Vowel Cube")); cube.setMinimumSize(200, 200); cube.resize(450, 450); cube.show(); return app.exec(); }
vowelcube.h
#ifndef VOWELCUBE_H #define VOWELCUBE_H #include <QGLWidget> #include <QRadialGradient> //使用OpenGL绘制立方体,使用QPainter绘制背景 //的渐变,接着使用renderText()绘制立方体角上的8个 //元音字母,最后使用QPainter和QTextDocument绘制图例。 //用户可以单击并拖动鼠标来旋转立方体,并且可以使用鼠标滚轮进行放大或缩小 class VowelCube : public QGLWidget { Q_OBJECT public: VowelCube(QWidget *parent = 0); ~VowelCube(); protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); private: void createGradient(); void createGLObject(); void drawBackground(QPainter *painter); void drawCube(); void drawLegend(QPainter *painter); GLuint glObject; QRadialGradient gradient; GLfloat rotationX; GLfloat rotationY; GLfloat rotationZ; GLfloat scaling; QPoint lastPos; }; #endif
vowelcube.cpp
1 #include <QtGui> 2 #include <QtOpenGL> 3 #include <cmath> 4 5 #ifndef GL_MULTISAMPLE 6 #define GL_MULTISAMPLE 0x809D 7 #endif 8 9 #include "vowelcube.h" 10 11 VowelCube::VowelCube(QWidget *parent) 12 : QGLWidget(parent) 13 { 14 //调用setFormat()使OpenGL的显示描述表支持饭走样。 15 setFormat(QGLFormat(QGL::SampleBuffers)); 16 17 //初始化私有变量 18 rotationX = -38.0; 19 rotationY = -58.0; 20 rotationZ = 0.0; 21 scaling = 1.0; 22 23 //设置填充背景的QRadialGradient 24 createGradient(); 25 //创建OpenGL立方体对象 26 createGLObject(); 27 28 setAutoBufferSwap( false ); 29 setAutoFillBackground( false ); 30 } 31 32 VowelCube::~VowelCube() 33 { 34 makeCurrent(); 35 //删除构造函数创建的OpenGL立方体对象 36 glDeleteLists(glObject, 1); 37 } 38 39 //绘制,在paintEvent()中创建一个QPainter,在进行纯OpenGL操作时 40 //保存和恢复其状态。 41 //QPainter的构造函数(或者QPainter::begin())自动调用glClear 42 //除非预先调用窗口部件的setAutoFillBackground(false) 43 //QPainter的析构函数(或者QPainter::end())自动调用QGLWidget::swapBuffers() 44 //切换可见缓存和离屏缓存,除非预先调用setAutoBufferSwap(false). 45 //当QPainter被激活,我们可以交叉使用纯OpenGL命令,只要在执行纯OpenGL命令之前保存OpenGL状态,之后恢复OpenGL状态 46 void VowelCube::paintEvent(QPaintEvent * /* event */) 47 { 48 QPainter painter( this ); 49 //绘制背景 50 drawBackground( &painter ); 51 //背景绘制结束 52 painter.end( ); 53 //绘制立方体 54 drawCube(); 55 //绘制开始 56 painter.begin(this); 57 //使用HTML文字设置QTextDocument对象 58 drawLegend(&painter); 59 painter.end( ); 60 swapBuffers( ); 61 } 62 63 //鼠标按下事件 64 void VowelCube::mousePressEvent(QMouseEvent *event) 65 { 66 lastPos = event->pos(); 67 } 68 69 //鼠标移动事件 70 void VowelCube::mouseMoveEvent(QMouseEvent *event) 71 { 72 GLfloat dx = GLfloat(event->x() - lastPos.x()) / width(); 73 GLfloat dy = GLfloat(event->y() - lastPos.y()) / height(); 74 75 if (event->buttons() & Qt::LeftButton) { 76 rotationX += 180 * dy; 77 rotationY += 180 * dx; 78 update(); 79 } else if (event->buttons() & Qt::RightButton) { 80 rotationX += 180 * dy; 81 rotationZ += 180 * dx; 82 update(); 83 } 84 lastPos = event->pos(); 85 } 86 87 //鼠标滚动的事件,调用update 88 void VowelCube::wheelEvent(QWheelEvent *event) 89 { 90 double numDegrees = -event->delta() / 8.0; 91 double numSteps = numDegrees / 15.0; 92 scaling *= std::pow(1.125, numSteps); 93 update(); 94 } 95 96 //使用蓝色渐变色设置QRadialGradient 97 void VowelCube::createGradient() 98 { 99 //确保指定的中心和焦点坐标根据窗口部件大小进行调整 100 gradient.setCoordinateMode(QGradient::ObjectBoundingMode); 101 //位置用0和1之间的浮点数表示,0对应焦点坐标,1对应圆的边缘 102 gradient.setCenter(0.45, 0.50); 103 gradient.setFocalPoint(0.40, 0.45); 104 gradient.setColorAt(0.0, QColor(105, 146, 182)); 105 gradient.setColorAt(0.4, QColor(81, 113, 150)); 106 gradient.setColorAt(0.8, QColor(16, 56, 121)); 107 } 108 109 //创建OpenGL列表,该列表保存绘制的立方体的边。 110 void VowelCube::createGLObject() 111 { 112 makeCurrent(); 113 114 glShadeModel(GL_FLAT); 115 116 glObject = glGenLists(1); 117 glNewList(glObject, GL_COMPILE); 118 qglColor(QColor(255, 239, 191)); 119 glLineWidth(1.0); 120 121 glBegin(GL_LINES); 122 glVertex3f(+1.0, +1.0, -1.0); 123 glVertex3f(-1.0, +1.0, -1.0); 124 glVertex3f(+1.0, -1.0, -1.0); 125 glVertex3f(-1.0, -1.0, -1.0); 126 glVertex3f(+1.0, -1.0, +1.0); 127 glVertex3f(-1.0, -1.0, +1.0); 128 glEnd(); 129 130 glBegin(GL_LINE_LOOP); 131 glVertex3f(+1.0, +1.0, +1.0); 132 glVertex3f(+1.0, +1.0, -1.0); 133 glVertex3f(+1.0, -1.0, -1.0); 134 glVertex3f(+1.0, -1.0, +1.0); 135 glVertex3f(+1.0, +1.0, +1.0); 136 glVertex3f(-1.0, +1.0, +1.0); 137 glVertex3f(-1.0, +1.0, -1.0); 138 glVertex3f(-1.0, -1.0, -1.0); 139 glVertex3f(-1.0, -1.0, +1.0); 140 glVertex3f(-1.0, +1.0, +1.0); 141 glEnd(); 142 143 glEndList(); 144 } 145 146 void VowelCube::drawBackground(QPainter *painter) 147 { 148 painter->setPen(Qt::NoPen); 149 painter->setBrush(gradient); 150 painter->drawRect(rect()); 151 } 152 153 //绘制立方体 154 void VowelCube::drawCube() 155 { 156 glPushAttrib(GL_ALL_ATTRIB_BITS); 157 158 glMatrixMode(GL_PROJECTION); 159 glPushMatrix(); 160 glLoadIdentity(); 161 GLfloat x = 3.0 * GLfloat(width()) / height(); 162 glOrtho(-x, +x, -3.0, +3.0, 4.0, 15.0); 163 164 glMatrixMode(GL_MODELVIEW); 165 glPushMatrix(); 166 glLoadIdentity(); 167 glTranslatef(0.0, 0.0, -10.0); 168 glScalef(scaling, scaling, scaling); 169 170 glRotatef(rotationX, 1.0, 0.0, 0.0); 171 glRotatef(rotationY, 0.0, 1.0, 0.0); 172 glRotatef(rotationZ, 0.0, 0.0, 1.0); 173 174 //设置反走样 175 glEnable(GL_MULTISAMPLE); 176 177 //绘制立方体 178 glCallList(glObject); 179 180 //设置文字颜色和字体 181 setFont(QFont("Times", 24)); 182 qglColor(QColor(255, 223, 127)); 183 184 //绘制字符,renderText使文字不变形 185 renderText(+1.1, +1.1, +1.1, QChar('a')); 186 renderText(-1.1, +1.1, +1.1, QChar('e')); 187 renderText(+1.1, +1.1, -1.1, QChar('o')); 188 renderText(-1.1, +1.1, -1.1, QChar(0x00F6)); 189 renderText(+1.1, -1.1, +1.1, QChar(0x0131)); 190 renderText(-1.1, -1.1, +1.1, QChar('i')); 191 renderText(+1.1, -1.1, -1.1, QChar('u')); 192 renderText(-1.1, -1.1, -1.1, QChar(0x00FC)); 193 194 glMatrixMode(GL_MODELVIEW); 195 glPopMatrix(); 196 197 glMatrixMode(GL_PROJECTION); 198 glPopMatrix(); 199 200 glPopAttrib(); 201 } 202 203 204 //使用HTML文字设置QTextDocument对象,在半透明的蓝色矩形上绘制它们 205 void VowelCube::drawLegend(QPainter *painter) 206 { 207 const int Margin = 11; 208 const int Padding = 6; 209 210 QTextDocument textDocument; 211 textDocument.setDefaultStyleSheet("* { color: #FFEFEF }"); 212 textDocument.setHtml("<h4 align="center">Vowel Categories</h4>" 213 "<p align="center"><table width="100%">" 214 "<tr><td>Open:<td>a<td>e<td>o<td>ö" 215 "<tr><td>Close:<td>ı<td>i<td>u<td>ü" 216 "<tr><td>Front:<td>e<td>i<td>ö<td>ü" 217 "<tr><td>Back:<td>a<td>ı<td>o<td>u" 218 "<tr><td>Round:<td>o<td>ö<td>u<td>ü" 219 "<tr><td>Unround:<td>a<td>e<td>ı<td>i" 220 "</table>"); 221 textDocument.setTextWidth(textDocument.size().width()); 222 223 QRect rect(QPoint(0, 0), textDocument.size().toSize() 224 + QSize(2 * Padding, 2 * Padding)); 225 painter->translate(width() - rect.width() - Margin, 226 height() - rect.height() - Margin); 227 painter->setPen(QColor(255, 239, 239)); 228 painter->setBrush(QColor(255, 0, 0, 31)); 229 painter->drawRect(rect); 230 231 painter->translate(Padding, Padding); 232 textDocument.drawContents(painter); 233 }