10 rotationX += 180 * dy;
11 rotationY += 180 * dx;
12 updateGL();
13 } else if (event->buttons() & Qt::RightButton) {
14 rotationX += 180 * dy;
15 rotationZ += 180 * dx;
16 updateGL();
17 }
18 lastPos = event->pos();
19 }
Функции класса QWidget mousePressEvent() и mouseMoveEvent() переопределяются, чтобы разрешить пользователю поворачивать изображение щелчком мышки и ее перемещением. Левая кнопка мышки позволяет пользователю поворачивать вокруг осей x и у, а правая кнопка мышки — вокруг осей x и z.
После модификации переменных rotationX и rotationY или rotationZ мы вызываем функцию updateGL() для перерисовки сцены.
01 void Tetrahedron::mouseDoubleClickEvent(QMouseEvent *event)
02 {
03 int face = faceAtPosition(event->pos());
04 if (face != -1) {
05 QColor color = QColorDialog::getColor(faceColors[face], this);
06 if (color.isValid()) {
07 faceColors[face] = color;
08 updateGL();
09 }
10 }
11 }
Функция mouseDoubleClickEvent() класса QWidget переопределяется, чтобы разрешить пользователю устанавливать цвет грани тетраэдра с помощью двойного щелчка. Мы вызываем закрытую функцию faceAtPosition() для определения той грани, на которой находится курсор (если он вообще находится на какой-нибудь грани). При двойном щелчке по грани тетраэдра мы вызываем функцию QColorDialog::getColor() для получения нового цвета для этой грани. Затем мы обновляем массив цветов faceColors новым цветом, и мы вызываем функцию updateGL() для перерисовки экрана.
01 int Tetrahedron::faceAtPosition(const QPoint &pos)
02 {
03 const int MaxSize = 512;
04 GLuint buffer[MaxSize];
05 GLint viewport[4];
06 glGetIntegerv(GL_VIEWPORT, viewport);
07 glSelectBuffer(MaxSize, buffer);
08 glRenderMode(GL_SELECT);
09 glInitNames();
10 glPushName(0);
11 glMatrixMode(GL_PROJECTION);
12 glPushMatrix();
13 glLoadIdentity();
14 gluPickMatrix(GLdouble(pos.x()),
15 GLdouble(viewport[3] - pos.y()),
16 5.0, 5.0, viewport);
17 GLfloat x = GLfloat(width()) / height();
18 glFrustum(-x, x, -1.0, 1.0, 4.0, 15.0);
19 draw();
20 glMatrixMode(GL_PROJECTION);
21 glPopMatrix();
22 if (!glRenderMode(GL_RENDER))
23 return -1;
24 return buffer[3];
25 }
Функция faceAtPosition() возвращает номер грани для заданной точки виджета или —1, если данная точка не попадает на грань. Программный код этой функции, выполненной с помощью средств OpenGL, немного сложен. Фактически мы переводим работу в режим GL_SELECT, чтобы воспользоваться возможностями OpenGL по идентификации элементов изображения, и затем получаем номер грани (ее «имя») из записи нажатия OpenGL.
Ниже приводится файл main.cpp:
01 #include <QApplication>
02 #include <iostream>
03 #include "tetrahedron.h"
04 using namespace std;
05 int main(int argc, char *argv[])
06 {
07 QApplication app(argc, argv);
08 if (!QGLFormat::hasOpenGL()) {
09 cerr << "This system has no OpenGL support" << endl;
10 return 1;
11 }
12 Tetrahedron tetrahedron;
13 tetrahedron.setWindowTitle(QObject::tr("Tetrahedron"));
14 tetrahedron.resize(300, 300);
15 tetrahedron.show();
16 return app.exec();
17 }
Если система пользователя не поддерживает OpenGL, мы выдаем на консоль сообщение об ошибке и сразу же возвращаем управление.
Для сборки приложения совместно с модулем QtOpenGL и системной библиотекой OpenGL файл .pro должен содержать следующий элемент:
QT += opengl
Этим заканчивается разработка приложения Тетраэдр. Более подробную информацию о модуле QtOpenGL вы найдете в справочной документации по классам QGLWidget, QGLFormat, QGLContext, QGLColormap и QGLPixelBuffer.
Глава 9. Технология «drag-and-drop»
Технология «drag-and-drop» («перетащить и отпустить») является современным и интуитивным способом передачи информации внутри одного приложения или между разными приложениями. Она часто является дополнением к операциям с буфером обмена по перемещению и копированию данных.
В данной главе мы увидим, как можно добавить в приложение Qt возможность поддержки технологии «drag-and-drop» и как обрабатывать пользовательские форматы. Затем мы используем программный код этой технологии для реализации операций с буфером обмена. Такое повторное использование данного программного кода возможно благодаря тому, что оба механизма основаны на применении одного класса QMimeData — базового класса, обеспечивающего представление данных в нескольких форматах.