Qpainter как рисовать
Перейти к содержимому

Qpainter как рисовать

  • автор:

Обработчик paintEvent. Рисование при помощи QPainter

Метод paintEvent для виджетов является обработчиком для события типа «перерисовка виджета». Этот метод вызывается при создании виджета, а также при необходимости его перерисовать, например, в результате изменения размеров виджета.

Это событие можно также создать принудительно, если вызвать для объекта класса метод repaint() .

Возможный вид метода paintEvent :

void Widget::paintEvent(QPaintEvent *event)
QPainter painter(this);
painter.drawLine(0, 0, width() — 1, height() — 1);
painter.drawLine(0, height() — 1, width() — 1, 0);
>

В этом примере рисование производится при помощи объекта QPainter. Этот объект позволяет рисовать графические примитивы — отрезки, окружности и эллипсы, прямоугольники и т.д.

В начале создается объект класса QPainter, привязанный к виджету. Затем используя методы рисования QPainter на этом объекте можно рисовать примитивы. Список возможных методов рисования можно найти в документации на QPainter.

drawLine — нарисовать линию.

drawEllipse — нарисовать эллипс или окружность.

drawRect — нарисовать прямоугольник.

drawPolygon — нарисовать многоугольник.

Чтобы узнать текущие размеры виджета используются методы width() и height() .

При рисовании можно задать параметры пера (Pen) и кисти (Brush). Pen определяет стиль рисуемых линий, окружностей, границ прямоугольника. Brush определяет тип внутренней заливки объектов.

Для установки пера используется метод setPen, которому в качестве параметра необходимо передать объект класса QPen. Примеры использования можно найти в документации.

Для установки кисти используется метод setBrush и параметр класса QBrush.

Как заставить Qpainter рисовать на нужном виджете.

Есть форма, на которой много чего, включая один пустой виджет graphArea. QPainter создается следующим образом:

fPainter = new QPainter(ui->graphArea); 

После чего рисую прямоугольник:

fPainter->begin(this); fPainter->setRenderHint(QPainter::Antialiasing); fPainter->setBrush(QColor(255,255,255)); fPainter->drawRect(0,0,ui->graphArea->width(),ui->graphArea->height()); fPainter->end(); 

А рисуется он начиная от левого верхнего угла формы, а не на виджете. Как заставить его рисовать на виджете? На чем вообще лучше рисовать? UPD: По совету @1101_debian пытаюсь рисовать теперь на QGraphicsView. Вот весь код paintEvent : fPainter = new QPainter(this); QGraphicsView *pGraphArea = ui->graphArea;

fPainter->begin(pGraphArea); fPainter->setRenderHint(QPainter::Antialiasing); fPainter->setPen(Qt::black); fPainter->drawRect(pGraphArea->x(),pGraphArea->y(),pGraphArea->width(),pGraphArea->height()); for (int i= pGraphArea->x(); i < pGraphArea->width(); i += 96/2.54) for (int j = pGraphArea->y(); j < pGraphArea->height(); j += 96/2.54) fPainter->drawPoint(i,j); fPainter->end(); event->ignore(); 

alt text

Получилось вот так: т.е. рисуется, но опять же за пределами QGraphicsView. Что не так делаю?

Qpainter как рисовать

На этом шаге рассмотрим рисование заполненных фигур.

Для рисования фигур также применяются методы, использующие перо QPen и кисть QBrush. Если требуется нарисовать только контур фигуры, без заполнения, то для этого методом QPainter::setBrush() нужно установить значение стиля кисти QBrush::NoBrush.

А для рисования фигуры без контурной линии можно методом QPainter::setPen() установить стиль пера QPen::NoPen.

Метод drawRect() рисует прямоугольник. В него передаются следующие параметры: координаты (X, Y) верхнего левого угла, ширина и высота. В этот метод можно передать также объект класса QRect (рис. 1).

Рис.1. Рисование прямоугольника

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(QColor(r,g,b,255), Qt::DiagCrossPattern)); painter.setPen(QPen(QColor(r,g,b,255), 5, Qt::DashLine)); painter.drawRect(QRect(10, 10, 280, 180));

Файлы приложения можно взять здесь.

Метод drawRoundRect() рисует прямоугольник с закругленными углами. Закругленность углов достигается с помощью четвертинок эллипса. Последние два параметра метода задают, насколько сильно должны быть закруглены углы в направлениях осей координат X и Y соответственно. При передаче нулевых значений углы не будут закруглены, а при присвоении им значения 100 прямоугольник превратится в эллипс. Прямоугольную область можно задавать объектом класса QRect (рис. 2).

Рис.2. Прямоугольник с закругленными углами

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(Qt::green)); painter.setPen(QPen(Qt::black)); painter.drawRoundRect(QRect(10, 10, 280, 180), 30, 30);

Файлы приложения можно взять здесь.

Метод drawEllipse() рисует заполненный эллипс, размеры и расположение которого задаются прямоугольной областью (рис. 3).

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(Qt::green, Qt::CrossPattern)); painter.setPen(QPen(Qt::red, 5, Qt::DotLine)); painter.drawEllipse(QRect(10, 10, 280, 180));

Файлы приложения можно взять здесь.

Метод drawChord() рисует хорду. Размеры и расположение эллипса задаются прямоугольной областью, а отображаемая часть — двумя последними параметрами, представляющими собой значения углов. Углы задаются в единицах, равных одной шестнадцатой градуса. Начальная и конечная точки будут соединены прямой линией. При положительных значениях двух последних параметров (углов) начальная точка перемещается вдоль кривой эллипса против часовой стрелки. Предпоследний параметр задает начальный угол. Последний параметр задает угол, под которым кривые должны пересекаться (рис. 4).

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(Qt::yellow)); painter.setPen(QPen(Qt::blue)); painter.drawChord(QRect(10, 10, 280, 180), 45 * 16, 180 * 16);

Файлы приложения можно взять здесь.

Метод drawPie() рисует часть эллипса. Начальная и конечная точки соединяются с центром эллипса (рис. 5). Последние два параметра метода задаются в шестнадцатых долях градуса.

Рис.5. Круговая диаграмма

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(Qt::black, Qt::BDiagPattern)); painter.setPen(QPen(Qt::blue, 4)); painter.drawPie(QRect(10, 10, 280, 180), 90 * 16, 270 * 16);

Файлы приложения можно взять здесь.

Метод drawPolygon() рисует заполненный полигон, последняя из заданных вершин которого будет соединена с первой (рис. 6).

QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(QBrush(Qt::green)); painter.setPen(QPen(Qt::yellow)); int n = 8; QPolygonF polygon; for (int i = 0; i < n; ++i) < qreal fAngle = 2 * 3.14 * i / n; qreal x = 150 + cos(fAngle) * 90; qreal y = 100 + sin(fAngle) * 90; polygon painter.drawPolygon(polygon);

Файлы приложения можно взять здесь.

На следующем шаге рассмотрим запись команд рисования.

Qt/C++ - Урок 020. QPainter - знакомство с рисованием в Qt

Во фреймворке Qt имеется возможность рисовать как на графической сцене , так и прямо на виджетах. Для этого используется класс QPainter. Рисование объектов на виджетах может производится в функции paintEvent(*event) , которая вызывается при отрисовке виджета. В данном уроке будет производится работа именно с этой функцией. В ней будет создаваться объект класса QPainter, и с его помощью будет рисоваться круг. При этом рисование круга будет зависеть от трех объектов класса QRadioButton. В зависимости от того, какой радиобаттон выбран, будет выбираться и цвет круга, если же ни один радиобаттон не будет выбран, то круг будет рисоваться белого цвета.

Структура проекта для QPainter

  • painter.pro - профайл проекта;
  • widget.h - заголовочный файл класса, в котором и производится работа с QPainter;
  • widget.cpp - файл исходных кодов по работе с QPainter;
  • main.cpp - запускающий файл проекта;
  • widget.ui - интерфейс приложения.

widget.ui

В дизайнере форм добавляем в виджет GroupBox с радиобаттонами и вертикальный spacer.

Внешний вид приложения

widget.h

В данном файле только определяем метод paintEvent() .

#ifndef WIDGET_H #define WIDGET_H #include #include namespace Ui < class Widget; >class Widget : public QWidget < Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); protected: /* Определяем виртуальный метод родительского класса * для отрисовки содержимого виджета * */ void paintEvent(QPaintEvent *event); private slots: void on_radioButton_red_clicked(); void on_radioButton_green_clicked(); void on_radioButton_blue_clicked(); private: Ui::Widget *ui; >; #endif // WIDGET_H

widget.cpp

А вот логика работы приложения полностью помещается в данный файл. В методе paintEvent() реализуем опрос радиобаттонов и по их состоянию рисуем круг на основном виджете.

#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) < ui->setupUi(this); > Widget::~Widget() < delete ui; >/* Метод, в котором происходит рисование * */ void Widget::paintEvent(QPaintEvent *event) < Q_UNUSED(event); QPainter painter(this); // Создаём объект отрисовщика // Устанавливаем кисть абриса painter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap)); /* Проверяем, какой из радиобаттонов выбран * */ if(ui->radioButton_red->isChecked()) < // Если красный, то отрисовываем красный круг painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); painter.drawEllipse(100, 50, 150, 150); >else if(ui->radioButton_green->isChecked()) < // Если зелёный, то отрисовываем зеленый круг painter.setBrush(QBrush(Qt::green, Qt::SolidPattern)); painter.drawEllipse(100, 50, 150, 150); >else if(ui->radioButton_blue->isChecked()) < // Если синий, то отрисовываем синий круг painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern)); painter.drawEllipse(100, 50, 150, 150); >else < // Если ничего не выбрано, то отрисовываем белый круг painter.setBrush(QBrush(Qt::white, Qt::SolidPattern)); painter.drawEllipse(100, 50, 150, 150); >> /* Как только один из радиобаттонов оказывается нажатым, * вызываем перерисовку содержимого виджета, * с которым работаем. * */ void Widget::on_radioButton_red_clicked() < repaint(); >void Widget::on_radioButton_green_clicked() < repaint(); >void Widget::on_radioButton_blue_clicked()

Итог

В результате у Вас получится приложение, показанное на ниже следующем рисунке. Демонстрация работы приложения присутствует в видеоуроке по данной статье.

Архив с исходниками: painter

Рекомендуем хостинг TIMEWEB

Рекомендуем хостинг TIMEWEB

Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Рекомендуемые статьи по этой тематике

  • Qt/C++ - Урок 076. Визуализация математических формул на Qt
  • QML - Урок 032. Создаём Custom QuickItem из C++ с использованием средств OpenGL
  • Qt/C++ - Урок 044. Сохранение объектов QGraphicsScene в файл векторной графики SVG
  • Qt/C++ - Урок 033. Работаем с QGraphicsObject вместо QGraphicsItem
  • Qt/C++ - Урок 027. Полиморфизм в Qt на примере геометрических фигур в QGraphicsScene
  • Qt/C++ - Урок 023. Перетаскивание QGraphicsItem на QGraphicsScene мышью
  • Qt/C++ - Урок 022. Как изменить курсор мыши в Qt
  • Qt/C++ - Урок 019. Рисуем треугольник в Qt5. Позиционирование в QGraphicsScene

По статье задано2 вопрос(ов)

Подписка на обсуждение 3
Подписка на раздел 340

Вам это нравится? Поделитесь в социальных сетях!

Доброго времени суток. Подскажите, пожалуйста, следующую вещь: что такое private slots: void on_radioButton_red_clicked(); void on_radioButton_green_clicked(); void on_radioButton_blue_clicked(); Откуда они взялись. Это какие - то предопределенные слоты класса radiobutton. Почему они исполняются при нажатии переключателей. Хоть убей, не пойму. Никакой инфы не нашел. Где они задаются привязанными к переключателям При попытке изменить имя слотов, они перестают работать. Сформулирую вопрос иначе: Где связываются переключатели и эти три слота.

  • ИсходныйКот → ИсходныйКот
  • #
  • 22 марта 2017 г. 17:19

Зы, т.е. если, я переименовываю слот, скажем,с void on_radioButton_blue_clicked() на void blue_clicked() в файлах widget.h и widget.cpp, все компилируется, но, переключатель radioButton_blue перестает работать ЗЫ: компилирую пример в Visual Studio. Creatorom и Designerom не пользуюсь. Эти слоты привязываются где - то в них?

Evgenii Legotckoi

  • Evgenii Legotckoi → ИсходныйКот
  • #
  • 22 марта 2017 г. 18:02

Да. Совершенно верно. Данные слоты создаются через дизайнер. Если в дизайнере кликнуть правой кнопкой мыши на какой-то объект и выбрать создание слота clicked() , то будет выглядеть примерно так, как показано в примере.

Qt имеет этап предкомпиляции, когда создаются всякие мок файлы, и в данном случае привязка идёт по текстовому наименованию слота. Если слот не находится, то он не подключается во время компиляции.

Вы должны будете найти подключение этих слотов в ui_widget.h , который автоматически создаётя во время компиляции.

  • ИсходныйКот → Evgenii Legotckoi
  • #
  • 22 марта 2017 г. 20:53

Понятно,спасибо,посмотрю. У нас,в виду исторических обстоятельств,весь код писан чисто в vs,без использования креатора(когда собирали qt под студии,креатор,даже,не компилировали),все интерфейсы писались через кодирование,и,все эти ui для меня темный лес. интересно расширить познания в этой области))

Evgenii Legotckoi

  • Evgenii Legotckoi → ИсходныйКот
  • #
  • 23 марта 2017 г. 4:35

Проект, в котором я работаю на данный момент развивается уже более 5-ти лет. Я в нём работаю последние 8 месяцев. Интерфейс полностью написан на Ui, причём с использованием плагинов для Qt Designer, также над продуктом работает команда переводчиков. В продукте сотни диалоговых окон. И из своих наблюдений могу сказать, что если бы не использовались Ui, то в какой-то момент работать стало бы очень грустно, причём не только программистам, но и переводчикам, поскольку тот же самый Qt Linguist, поддерживает отображение Ui файлов, что гораздо удобнее, чем смотреть в код и не понимать, к какому всё-таки окну это относится.

  • ИсходныйКот → Evgenii Legotckoi
  • #
  • 23 марта 2017 г. 8:16

У программы нас не имеют статических окошек, как таковых - окна могут быть совершенно различными в зависимости от множества условий, и, "лепятся", прямо, на лету, при запуске. Те, кто начинал проекты, выбрали чистый код, и, тем кто с ними работает сейчас, приходится делать все без использования ui, либо, все переписывать, а, это не на один год работы - проекты большие,ведутся лет 20, множество модулей написаны на всем, что можно только себе вообразить, начиная от ассемблера(работаем с железом и драйверами, в том числе) и заканчивая C#, и, все это завязано на кроссплатформенный qt, поскольку, поддерживается и Линупс. Старая команда отвалила, набрали новыю. Переписывать все жестоко, да, и, опыта у меня маловато

  • ИсходныйКот → Evgenii Legotckoi
  • #
  • 23 марта 2017 г. 10:03

Увидел, еще, один интересный момент. Вы написали про редактирование слота clicked(), а, в дизайнере я этой возможности не нашел, но, тут такой момент. у меня qt собрана самостоятельно, без creator-a, есть, только, дизайнер. А, в дизайнере нет поддержки слотов(по правой клавише мыши). Потом, поставил Creator, а, там, дизайнер открывается в контексте проекта, вот, там создание слота clicked,уже есть. Про этот момент я не знал, поэтому, и, не нашел в дизайнере, как создать слот. В новых версиях qt создание слотов из дизайнера вынесли.

Evgenii Legotckoi

  • Evgenii Legotckoi → ИсходныйКот
  • #
  • 23 марта 2017 г. 11:13

Но согласитесь, что отсутствие ui - это проблема того, что проекты давно развиваются, имеется много легаси кода и того, что на момента развития проектов и сам Qt не был так сильно развит. Например, Qt4 и Qt5 довольно сильно различаются, да даже Qt 5.6 очень отличается от Qt 5.8 по некоторым модулям, особенно если полезть в сторону QML. А после пары калымов я вовсе зарёкся браться за проекты с Qt4, особенно те, которые пишутся на устаревших версиях VS. Наверняка, многое можно стандартизировать и шаблонизировать. В нашем проекте сотни диалоговых окон с ui, но все они создаются и наполняются динамически. А также имеют всего несколько базовых классов. Просто различные вкладки интерфейса скрываются или добавляются в зависимости от этих самых условий, про которые вы сказали. Ну а так да. - Переписывать всё действительно жёстко, если проекты давно развиваются, но это уже немного другая история.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *