§4 Рисование. Класс QPainter


QPainter

Класс Qpainter предоставляет большой набор функций для рисования на различных виджетах. При этом, этот класс можно использовать как для работы с примитивами, так и с изображениями и текстом. Познакомимся с этим классом. Для этого создайте новый проект. Мы будем рисовать непосредственно на форме. Подготовьте форму установив цвет фона белый. Система координат – это экранная система, в которой центром является левый верхний угол, а ось Y направлена вниз. Приводка координат делается к текущему объекту на котором производится рисование. Перейдите в редактор и в заголовочном файле widget.h объявите защищенный метод paintEvent():

protected:
    void paintEvent(QPaintEvent*);    

Этот метод будет использоваться для перерисовки виджета на котором происходит событие связанное с рисованием. О том, что такое событие произошло сообщает событийный класс QPaintEvent(). Реализацию этого метода мы сделаем в файле widget.cpp.
Для того, чтобы нарисовать какую-нибудь фигуру мы должны знать как реализована геометрия в Qt. Для задания точки используется классы QPoint и QPointF (последний использует для координат действительные числа). Точка обладает двумя координатами x и y, доступ к которым можно получить соответствующими функциями x() и y(). Координаты могут быть изменены функциями setX() и setY() (или используя ссылки rx и ry).

QPoint p(1, 2);
p.rx()--;   // (0, 2)
p.ry()++;   // (0, 3)

Точки могут рассматриваться как векторы, которые исходят из начала координат. Соответственно, над ними можно производить все соответствующие операции для векторов: сложение, вычитание, умножение векторов, умножение вектора на число и др.

Рис. 1

QPoint p(1, 2);
p.setX(p.x() + 1); // x == 2
p += QPoint(1, 0); // x == 3
p.rx()++;          // x == 4

Скалярное произведение векторов можно вычислить с помощью метода dotProduct():

QPoint p( 3, 7);
QPoint q(-1, 4);
int lengthSquared = QPoint::dotProduct(p, q);   // 25

Точки могут сравниваться друг с другом. Методом isNull() можно узнать находится ли точка в начале координат.
Другие операции и функции доступные в этом классе см. здесь.
Фигуры, которые мы будем рисовать требуют передачи, в качестве параметра, значение размера, т. е. ширины и высоты. За определение размера отвечают классы QSize и QSizeF. Значение ширины можно получить методом width(), а высоты – height(). Установить новую ширину и высоту можно методами setWidth() и setHeight(). Методы rwidth() и rheight() возвращают соответствующие ссылки на значение ширины и высоты. Другие методы класса см. здесь.
Еще один вспомогательный класс – это QRect и QRectF. Этот класс хранит прямоугольную область которую можно определить как совокупность объектов двух классов QPoint и QSize:

QRect::QRect(int x, int y, int width, int height)

Прямоугольные области можно определять и непосредственной передачей числовых значений.

QRect r1(100, 200, 11, 16);
QRect r2(QPoint(100, 200), QSize(11, 16));

Методы этого класса вы можете посмотреть здесь.

Перо и кисть

Следующие инструменты которые нам понадобятся для рисования – это перо и кисть. С помощью пера рисуются контуры фигур. Соответственно, основные параметры пера – это толщина линии, её стиль и цвет. Управляет пером класс QPen(). Установите перо в классе QPainter можно следующим образом:

QPainter painter(this);
QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);

Это равносильно следующему коду:

QPainter painter(this);
QPen pen;  // перо по умолчанию

pen.setStyle(Qt::DashDotLine); // стиль пера (точка-тире)
pen.setWidth(3); // толщина пера
pen.setBrush(Qt::green); // цвет пера
pen.setCapStyle(Qt::RoundCap); // стиль конца линии (закругленный)
pen.setJoinStyle(Qt::RoundJoin); // стиль закругления угла

painter.setPen(pen);

Методы и стили пера см. здесь.
Кисть используется для заливки замкнутых контуров таких как эллипс или прямоугольник. Руководит всем класс QBrush. Кисть имеет два параметра – это цвет пера и стиль пера. Стили пера и методы класса QBrush см. здесь.

Точки и линии

Теперь мы сможем, наконец, что-то нарисовать. И первое, что мы нарисуем – это точки. Метод класса QPainter, который рисует точку – drawPoint(). В качестве параметра ему необходимо передать объект QPoint. Составим программу рисования сетки. Она пригодится в проекте для вывода графика функции. Обратите внимание на то, что перед использованием класса QPainter необходимо включить одноименный заголовочный файл. Приводим листинг файла widget.cpp полностью.

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    setFixedSize(800, 600); // Фиксированный размер окна
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);

    QPen pen;  // перо по умолчанию
    pen.setWidth(3); // толщина пера
    pen.setBrush(Qt::gray); // цвет пера
    painter.setPen(pen); // применяем настройки пера

    int W = width(); // Ширина и высота окна
    int H = height();
    int d = 20; // Отступ от края окна
    int h = 50; // Размер ячейки
    int t = 5; // Плотность точек

    for (int i = d; i < W - d; i+=h) {
        for (int j = d; j < H - d - t; j+=t)
            painter.drawPoint(QPoint(i, j));
        for (int j = d; j < W - d - t; j+=t)
            painter.drawPoint(QPoint(j, i));
    }
}

Чтобы зафиксировать размеры окна мы применили метод setFixedSize() класса QWidget. Результат работы программы:

Рис. 2

Нарисуем на этом фоне график функции f(x) = x2, т. е. параболу. Но есть загвоздка. В существующих координатах мы можем увидеть только половину параболы. К тому же её ветви будут направлены вниз. В классе Qpainter существует функция, которая позволяет изменить начало координат – translate(). Для того, чтобы изменить координаты или другие настройки объектов на время рисования какой-либо задачи, но при этом сохранить предыдущие установки, применяются методы save() и restore(). Таким образом, мы можем на время перейти к другим координатам в нижней части окна, по центру, а также использовать другие установки для пера. Добавьте следующий фрагмент в файл widget.cpp:

    painter.save(); // Сохраняем предыдущие настройки
    pen.setWidth(3); // толщина пера
    pen.setBrush(Qt::red); // цвет пера
    painter.setPen(pen);
    QPoint OO(W/2 + d, H - d - d/2); // Определяем новое начало координат
    painter.translate(OO); // Перемещаем начало координат
    for (int i = -W/2; i < W/2; i++) {
        QPointF coord;
        coord.rx() = i;
        coord.ry() = (-1) * coord.rx() * coord.rx() * 0.01;
        painter.drawPoint(QPointF(coord.rx(), coord.ry()));
    }
    painter.restore(); // возвращение к предыдущим настройкам

Результат работы программы:

Рис. 3

Цвет

Для работы с цветом используется класс QColor. Поддерживаются цветовые модели RGB, HSV, CMYK и HSL, а также предустановленные цвета. Подробные сведения о классе см. здесь. Для того, чтобы задать цвет в модели RGB или RGBA (последняя с альфа-каналом) можно использовать структуру QRgb, которая создаётся с помощью функций qRgb() или qRgba(), или использовать метод setRgb(), например, так:

QColor rgb1;
QColor rgb2;
QRgb color = qRgb(255, 0, 0);
rgb1(color);
rgb2.setRgb(0, 255, 0);

Значение цвета можно передать в виде шестнадцатеричного числа:

QRgb color2 = 0x00FF0000;

В пространстве имен Qt определены 19 предопределенных цветов. Некоторые из них мы используем в программах этого урока.

Рисование замкнутых фигур

Для рисования и заливки замкнутых фигур используются следующие методы:

  • drawArc – рисование дуги
  • drawChord – рисование хорды окружности
  • drawEllipse – рисование эллипса
  • drawLine – рисование линии
  • drawPie – рисование сектора окружности
  • drawPolygon – рисование многоугольника
  • drawRect – рисование прямоугольника
  • drawRoundedRect – рисование многоугольника с закругленными углами
и многие другие. Подробные сведения о методах рисования см. здесь.
Создайте новый проект. Цель проекта – нарисовать в окне два квадрата в центре которых будут нарисованы круг и треугольник. Чтобы создать круг или квадрат необходимо в конструктор передать в качестве параметра объект QRect.

void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setPen(QPen(Qt::red, 3, Qt::SolidLine, Qt::FlatCap));
    painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern));
    QPoint pt(50, 50);
    QSize size(200, 200);
    QRect r(pt, size);
    // Рисуем прямоугольник
    painter.drawRect(r);
    painter.setPen(QPen(Qt::green, 3, Qt::DotLine));
    painter.setBrush(QBrush(Qt::yellow, Qt::SolidPattern));
    // Параметры можно предавать в методе
    painter.drawRect(QRect(300, 50, 200, 200));
    // Рисуем окружность внутри первого квадрата
    // drawEllipse() рисует эллипс в заданной прямоугольной области
    painter.setPen(QPen(Qt::gray, 3, Qt::DotLine));
    painter.setBrush(QBrush(Qt::magenta, Qt::SolidPattern));
    painter.drawEllipse(QRect(100, 100, 100, 100));
    // Внутри второго квадрата рисуем треугольник
    // Вначале объявляем полигон
    QPolygon tri;
    // Устанавливаем точки
    tri << QPoint(400, 100) << QPoint(450, 200) << QPoint(350, 200);
    painter.setPen(QPen(Qt::red, 3, Qt::DashLine));
    painter.setBrush(QBrush(Qt::gray, Qt::SolidPattern));
    painter.drawPolygon(tri);
}

Результат работы программы:

Рис. 4
Задания
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...
Print Friendly, PDF & Email

Comments are closed.