Выбрать главу

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 — базового класса, обеспечивающего представление данных в нескольких форматах.