49 painter->setPen(thinPen);
50 painter->drawLine(0, -42, 0, -44);
51 }
52 painter->rotate(-DegreesPerMinute);
53 }
54 }
Мы вызываем функцию rotate() для поворота системы координат рисовальщика. В старой системе координат нулевая отметка находилась сверху; теперь нулевая отметка перемещается для установки соответствующего времени, которое остается до срабатывания таймера. После каждого поворота мы снова рисуем ручку таймера, поскольку его ориентация зависит от угла поворота.
В цикле for мы рисуем минутные отметки по внешней окружности и отображаем количество минут через каждые 5 минутных меток. Текст размещается в невидимом прямоугольнике под минутной отметкой. В конце каждой итерации цикла мы поворачиваем рисовальщик по часовой стрелке на 7°, что соответствует одной минуте. При рисовании минутной отметки следующий раз она будет отображаться в другом месте окружности, хотя мы передаем одни и те же координаты функциям drawLine() и drawText().
В этом программном коде в цикле for имеется незаметная погрешность, которая быстро стала бы очевидной, если бы мы выполнили больше итераций. При каждом вызове rotate() мы фактически умножаем текущую универсальную матрицу преобразования на матрицу поворота, получая новую универсальную матрицу преобразования. Ошибка округления чисел с плавающей точкой еще больше увеличивает неточность универсальной матрицы преобразования. Ниже показан один из возможных способов решения этой проблемы путем перезаписи программного кода с использованием save() и restore() для сохранения и восстановления первоначальной матрицы преобразования на каждом шаге итерации:
41 for (int i = 0; i <= MaxMinutes; ++i) {
42 painter->save();
43 painter->rotate(-i * DegreesPerMinute);
44 if (i % 5 == 0) {
45 painter->setPen(thickPen);
46 painter->drawLine(0, -41, 0, -44);
47 painter->drawText(-15, -41, 30, 25,
48 Qt::AlignHCenter | Qt::AlignTop,
49 QString::number(i));
50 } else {
51 painter->setPen(thinPen);
52 painter->drawLine(0, -42, 0, -44);
53 }
54 painter->restore();
55 }
При другом способе реализации таймера духовки нам нужно было бы самим рассчитывать координаты (x, y), используя функции sin() и cos() для определения их позиции на окружности. Но тогда нам все же пришлось бы выполнять перенос и поворот системы координат для отображения текста под некоторым углом.
Высококачественное воспроизведение изображения при помощи QImage
При рисовании мы можем столкнуться с необходимостью принятия компромиссных решений относительно скорости и точности. Например, в системах X11 и Mac OS X рисование по виджету QWidget или по пиксельной карте QPixmap основано на применении родного для платформы графического процессора (paint engine). В системе X11 это обеспечивает минимальную связь с Х—сервером; посылаются только команды рисования, а не данные реального изображения. Основным недостатком этого подхода является то, что возможности Qt ограничиваются родными для данной платформы средствами поддержки:
• в системе Х11 такие возможности, как сглаживание линий и поддержка дробных координат, доступны только в том случае, если Х—сервер использует расширение X Render;
• в системе Mac OS X родной графический процессор, обеспечивающий сглаживание линий, использует алгоритмы рисования многоугольников, которые отличаются от алгоритмов в X11 и Windows, что приводит к получению немного других результатов.
Когда точность важнее эффективности, мы можем рисовать по QImage и копировать результат на экран. В этом случае Qt всегда использует собственный внутренний графический процессор и результат на всех платформах получается идентичным. Единственное ограничение заключается в том, что QImage, по которому мы рисуем, должен создаваться с аргументом QImage::Format_RGB32 или QImage::Format_ARGB32_Premultiplied.