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 }