
Сохранение состояния. Рисование в Qt. Часть 3
Сегодня мы рассмотрим функционал QPainter, который является очень важным для эффективного применения данной библиотеки – это сохранение и восстановление состояния.
Это очень важно при создании сложных рисунков, так как позволяет делать код более компактным, понятным и эффективным.
Так как у нас места у нас мало, увеличим размер окна до 400х400
Сделать это вы можете в редакторе форм QTCreator.
Работать мы будем с кодом из первой части:
Удалим методы
void drawChildPicAbs();
void drawChildPicRel();
они нам не понадобятся.
Давайте разберемся, как работают методы save() и restore()
При вызове painter->save() происходит сохранение всех доступных настроек в о внутренний стэк.
Что такое стэк? Как правило, это область памяти, в которой объекты храниться в виде списка. Основной особенностью стэка является способ доступа к элементам списка. Вы всегда можете извлечь из стека только тот элемент, который был помещен в него последним. В общем стек работает как детская игрушка – пирамидка. На стержень можно надевать кольца, но снимать их можно строго последовательно.
Итак, когда мы вызываем save() текущее состояние помещается в стэк.
Когда нам нужно восстановить состояние мы вызываем restore(). При этом текущее состояние QPainter будет уничтожено!
Если в стеке остался один элемент, то будет восстановлено состояние этого элемента, неважно, сколько раз мы будем вызывать метод restore().
Давайте проверим это на примере.
Нарисуем несколько колец в квадрате, для этого добавим метод:
void MainWindow::drawRings()
{
QColor linesColor(0, 0, 255, 255);
QPen apen = QPen(linesColor);
apen.setWidth(3);
painter->setPen(apen);
painter->translate(QPoint(100,100));
painter->drawRect(QRect(0,0,250,250));
painter->translate(QPoint(50,50));
apen.setWidth(1);
painter->setPen(apen);
painter->drawEllipse(0, 0, 30,30);
painter->drawEllipse(-10, 0, 30,30);
painter->drawEllipse(10, 0, 30,30);
painter->drawEllipse(0, -10, 30,30);
painter->drawEllipse(0, 10, 30,30);
painter->translate(QPoint(100,0));
painter->drawEllipse(0, 0, 30,30);
painter->drawEllipse(-10, 0, 30,30);
painter->drawEllipse(10, 0, 30,30);
painter->drawEllipse(0, -10, 30,30);
painter->drawEllipse(0, 10, 30,30);
painter->translate(QPoint(0,100));
painter->drawEllipse(0, 0, 30,30);
painter->drawEllipse(-10, 0, 30,30);
painter->drawEllipse(10, 0, 30,30);
painter->drawEllipse(0, -10, 30,30);
painter->drawEllipse(0, 10, 30,30);
painter->translate(QPoint(-100,0));
painter->drawEllipse(0, 0, 30,30);
painter->drawEllipse(-10, 0, 30,30);
painter->drawEllipse(10, 0, 30,30);
painter->drawEllipse(0, -10, 30,30);
painter->drawEllipse(0, 10, 30,30);
}
У нас получился такой рисунок:
Стрелками я показал путь, по которому производилась трансляция.
Теперь если мне потребуется разместить ещё один орнамент, в центре, мне придется вычислять новое смещение, что не очень удобно, а если я захочу заполнить весь квадрат орнаментом, придется еще больше усложнять алгоритм.
А теперь давайте упростим метод.
Добавим отдельный метод для отрисовки орнамента
void MainWindow::drawOrnament(QPoint pos, QColor color)
{
painter->save();
QPen apen = QPen(color);
apen.setWidth(1);
painter->setPen(apen);
painter->translate(pos);
painter->drawEllipse(0, 0, 30,30);
painter->drawEllipse(-10, 0, 30,30);
painter->drawEllipse(10, 0, 30,30);
painter->drawEllipse(0, -10, 30,30);
painter->drawEllipse(0, 10, 30,30);
painter->restore();
}
Изменим метод drawRings()
void MainWindow::drawRings()
{
QColor linesColor(0, 0, 255, 255);
QPen apen = QPen(linesColor);
apen.setWidth(3);
painter->setPen(apen);
painter->translate(QPoint(100,100));
painter->drawRect(QRect(0,0,250,250));
drawOrnament(QPoint(50,50),linesColor);
drawOrnament(QPoint(50,100),linesColor);
drawOrnament(QPoint(100,50),linesColor);
drawOrnament(QPoint(100,100),linesColor);
drawOrnament(QPoint(150,50),linesColor);
drawOrnament(QPoint(150,100),linesColor);
}
У нас получился рисунок:
Как видите, код стал проще, и мы можем сразу работать с локальными координатами относительно левого верхнего угла квадрата.
Давайте заполним весь квадрат орнаментами, при этом, каждый из них, будет своего цвета.
void MainWindow::drawRings()
{
QColor linesColor(0, 0, 255, 255);
QPen apen = QPen(linesColor);
apen.setWidth(3);
painter->setPen(apen);
painter->translate(QPoint(100,100));
painter->drawRect(QRect(0,0,240,240));
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
QColor linesColor( QRandomGenerator::global()->bounded(240),
QRandomGenerator::global()->bounded(240),
QRandomGenerator::global()->bounded(240),
255);
drawOrnament(QPoint(15+30*i,15+30*j),linesColor);
}
}
}
У нас получиться
Заключение
Сегодня мы рассмотрели методы save() И restore() класса QPainter.
Мы разобрались, как они работают и написали небольшой тестовый проект, чтобы продемонстрировать работу методов save() и restore().
Добавить комментарий