[Предыдущая: Рисование и заливка] [Система рисования] [Следующая: Чтение и запись файлов изображений] Система координат
|
QRect(1, 2, 6, 4) | QLine(2, 7, 6, 1) |
Когда идет рисование, визуализация пикселя контролируется подсказкой визуализации (render hint) QPainter::Antialiasing.
Перечисление RenderHint используется для задания флагов QPainter'а, которое может или не может быть соблюдено любым имеющимся механизмом. Значение QPainter::Antialiasing указывает на то, что механизм должен сгладить края примитивов если это возможно, т.е. сгладить края используя разную интенсивность цвета.
Но по умолчанию рисовальщик ступенчатый и применяются другие правила: При визуализации пером толщиной в один пиксель пиксели формируемого изображения будут располагаться правее и ниже математически описанных точек. Например:
QPainter painter(this); painter.setPen(Qt::darkGreen); painter.drawRect(1, 2, 6, 4); | QPainter painter(this); painter.setPen(Qt::darkGreen); painter.drawLine(2, 7, 6, 1); |
При визуализации с помощью пера толщиной даже в несколько пикселей, пиксели будут визуализироваться симметрично вокруг математически описанных точек, причем при визуализации пером толщиной с нечетным количеством пикселем дополнительный пиксель будет визуализирован правее и ниже математической точки, как и в случае одного пикселя. Смотрите диаграммы QRectF ниже для конкретных примеров.
QRectF | ||
---|---|---|
Логическое представление | Перо шириной в один пиксель | |
Перо шириной в два пикселя | Перо шириной в три пикселя |
Обратите внимание на то, что по историческим причинам возвращаемое значение функций QRect::right() и QRect::bottom() отклоняется от истинного нижнего правого угла прямоугольника.
Функция QRect'а - right() - возвращает left() + width() - 1, а функция bottom() возвращает top() + height() - 1. Нижняя правая зелёная точка на диаграммах показывает возвращаемые этими функциями координаты.
Мы рекомендуем вам просто использовать вместо этого QRectF: Класс QRectF описывает прямоугольник в плоскости, используя для точности в качестве координат числа с плавающей точкой (QRect использует целочисленных координаты), а функции QRectF::right() и QRectF::bottom() выполняют возврат истинного нижнего правого угла.
В качестве альтернативы, используя QRect, примените x() + width() и y() + height() чтобы найти нижний правый угол, и избежать функций right() и bottom().
Если вы установили QPainter'у подсказку визуализации anti-aliasing, пиксели будут визуализироваться симметрично по обе стороны от математически описанных точек:
QPainter painter(this); painter.setRenderHint( QPainter::Antialiasing); painter.setPen(Qt::darkGreen); painter.drawRect(1, 2, 6, 4); | QPainter painter(this); painter.setRenderHint( QPainter::Antialiasing); painter.setPen(Qt::darkGreen); painter.drawLine(2, 7, 6, 1); |
По умолчанию, QPainter оперирует в собственной системе координат, связанной с устройством, но также он обладает полной поддержкой аффинных преобразований координат.
Вы можете масштабировать систему координат на заданное смещение используя функцию QPainter::scale(), используя функцию QPainter::rotate() вы можете вращать ее по часовой стрелке и вы можете ее транслировать (т.е. прибавить заданное смещение к точкам), используя функцию QPainter::translate().
nop | rotate() | scale() | translate() |
Вы также можете вращать систему координат вокруг начала координат используя функцию QPainter::shear(). Смотрите визуализацию сдвинутой системы координат в демонстрационной программе Аффинные преобразования. Все операции преобразования выполняются на матрице преобразования QPainter'а, которую вы можете найти используя функцию QPainter::worldTransform(). Матрица преобразует одну точку на плоскости в другую точку.
Если вам нужны неоднократные преобразования, вы можете также использовать объекты QTransform и функции QPainter::worldTransform() и QPainter::setWorldTransform(). В любой момент вы можете сохранить матрицу преобразований QPainter'а вызвав функцию QPainter::save(), которая сохраняет матрицу на внутреннем стеке. Функция QPainter::restore() извлекает ее из стека обратно.
Одно из часто необходимых применений матрицы преобразований - когда один и тот же код рисования повторно используется на различных устройствах рисования. Без преобразований результаты тесно связаны с разрешением устройства рисования. Принтеры имеют высокую разрешающую способность, например 600 точек на дюйм, тогда как экраны часто имеют разрешение между 72 и 100 точками на дюйм.
Пример "Analog Clock" | |
---|---|
Пример "Analog Clock" показывает, как рисовать содержимое пользовательского виджета, используя матрицу преобразования QPainter'а. Каталог примеров Qt предоставляет полный разбор примера. Здесь мы рассмотрим только функцию paintEvent() из примера, чтобы увидеть как мы можем использовать матрицу преобразований (т.е. функции матрицы QPainter'а) для рисования лицевой стороны часов. Мы рекомендуем скомпилировать и запустить этот пример перед тем, как вы продолжите чтение. В частности, попытайтесь изменить размеры окна до других размеров. | |
void AnalogClock::paintEvent(QPaintEvent *) { static const QPoint hourHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -40) }; static const QPoint minuteHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -70) }; QColor hourColor(127, 0, 127); QColor minuteColor(0, 127, 127, 191); int side = qMin(width(), height()); QTime time = QTime::currentTime(); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0); Сначала мы установим рисовальщика. Транслируем систему координат так, что точка (0, 0) располагается в центре виджета, вместо того чтобы быть в верхнем левом углу. Мы также масштабируем систему координат на величину side / 100, где side - ширина либо высота виджета, которая меньше по величине. Мы хотим, чтобы часы были квадратными даже если устройство не квадратное. Это даст нам квадратную область 200 x 200 с началом координат (0, 0) по центру, в которой мы можем рисовать. То, что мы рисуем будет показано в наибольшем возможном квадрате, который помещается в виджет. Смотрите также раздел Преобразование окно-область отображения. painter.save(); painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 3); painter.restore(); Мы нарисовали часовую стрелку повернув систему координат и вызвав QPainter::drawConvexPolygon(). Спасибо вращению, она нарисована в правильном направлении. Многоугольник задается массивом чередующихся значений x, y, сохраняемым в статической переменной hourHand (описанной в начале функции), которым соответствует четыре точки (2, 0), (0, 2), (-2, 0) и (0, -25). Вызовы QPainter::save() и QPainter::restore(), обрамляющие код, гарантируют что этот код не будет разрушен используемыми нами преобразованиями. painter.save(); painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); painter.drawConvexPolygon(minuteHand, 3); painter.restore(); Мы сделали тоже самое для минутной стрелки, которая описывается четырьмя точками (1, 0), (0, 1), (-1, 0) и (0, -40). Эти координаты определяют стрелку, которая тоньше и длиннее чем минутная стрелка. for (int j = 0; j < 60; ++j) { if ((j % 5) != 0) painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } В заключение мы рисуем лицевую часть часов, которая состоит из двенадцати коротких линий через 30-градусные интервалы. В конце рисовальщик поворачивается способом, который не очень удобен, но мы сделали это с рисованием так что это не имеет значения. |
Для демонстрации возможностей Qt для выполнения аффинных преобразований на операциях рисования, смотрите демонстрационную программу Аффинные преобразования, которая позволяет пользователю экспериментировать с операциями преобразования. Смотрите также пример Преобразования, который показывает как преобразования влияют на способ, которым QPainter визуализирует графические примитивы. В частности, он показывает как порядок преобразований оказывает влияние на результат.
Для получения дополнительной информации о матрице преобразований смотрите документацию по QTransform.
При рисовании с помощью QPainter'а мы указываем точки, используя логические координаты, которые затем преобразуются в физические координаты устройства рисования.
Отображение логических координат на физические координаты обрабатываются QPainter'ом мировым преобразованием worldTransform() (описываемым в разделе Преобразования) и QPainter'а - viewport() и window(). Область отображения представляет физические координаты, заданные произвольным прямоугольником. "Окно" описывает тот же прямоугольник в логических координатах. По умолчанию логическая и физическая системы координат совпадают и являются эквивалентными прямоугольнику устройства рисования.
Используя преобразование окно-область отображения вы можете сделать систему координат соответствующей вашим предпочтениям. Механизм также может быть использован для того, чтобы сделать код рисования независимым от устройства рисования. Вы можете, например, сделать так чтобы логические координаты простирались от (-50, -50) до (50, 50) с (0, 0) в центре вызвав функцию QPainter::setWindow():
QPainter painter(this); painter.setWindow(QRect(-50, -50, 100, 100));
Теперь логические координаты (-50,-50) соответствуют физическим координатам устройства рисования (0, 0). Независимый от устройства рисования ваш код рисования всегда будет работать в заданных логических координатах.
Установив прямоугольник "окна" или области просмотра, вы выполняете линейное преобразование координат. Обратите внимание на то, что каждый угол "окна" отображается в соответствующий угол области просмотра и наоборот. По этой причине обычно является хорошей идеей позволить области просмотра и "окну" поддерживать один и тот же коэффициент пропорциональности чтобы предотвратить искажение:
int side = qMin(width(), height()) int x = (width() - side / 2); int y = (height() - side / 2); painter.setViewport(x, y, side, side);
Если мы сделаем логическую систему координат квадратной, то используя функцию QPainter::setViewport() мы сможем сделать область просмотра также квадратной. В примере выше мы сделали её эквивалентной наибольшему квадрату, который помещается в прямоугольник устройства рисования. Учтя размер устройства рисования когда настраивается окно или область просмотра, возможно сохранить код рисования независимым от устройства рисования.
Обратите внимание на то, что преобразование окно-область отображения является только линейным преобразованием, т.е. оно не выполняет обрезание. Это означает, что если вы рисуете за пределами текущего установленного "окна", ваш рисунок будет трансформирован в область отображения используя тот же линейный алгебраический подход.
Область отображения, "окно" и матрица преобразования определяют, как логические координаты QPainter отобразятся на физические координаты устройства рисования. По умолчанию мировая матрица преобразований - единичная матрица, и настройки "окна" и области отображения эквивалентны настройкам устройства рисования, т.е. мировая система координат, "оконная" система координат и система координат устройства являются эквивалентными, но как мы видели, системы могут управляться с использованием операции преобразования и преобразование окно-область отображения. Рисунок выше иллюстрирует процесс.
Смотрите также Пример "Analog Clock" и Пример "Transformations".
[Предыдущая: Рисование и заливка] [Система рисования] [Следующая: Чтение и запись файлов изображений]
Авторские права © 2010 Nokia Corporation и/или её дочерние компании | Торговые марки | Qt 4.6.4 |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |