Как сделать рисование в qt

Обновлено: 06.07.2024

Первым шагом к созданию пользовательских виджетов в PyQt5 является понимание операций с растровой (пиксельной) графикой. Все стандартные виджеты рисуются в виде растровых изображений на прямоугольном «холсте», который формирует форму виджета. Как только вы поймете, как это работает, вы сможете рисовать любые виджеты!

Растровое изображение – это прямоугольная сетка из пикселей, где каждый пиксель хранится отдельно в виде определенного количества битов. В отличие от векторной графики, где изображение хранится в виде серии инструкций по рисованию, которые повторяются для формирования изображения.

В этом руководстве мы рассмотрим QPainter — API Qt для выполнения операций с растровой графикой и основу для рисования собственных виджетов. Мы выполним некоторые основные операции рисования и, наконец, соберем все вместе, чтобы создать собственное маленькое приложение Paint.

Операции рисования растровых изображений в Qt обрабатываются через класс QPainter. Это общий интерфейс, который можно использовать для рисования на различных поверхностях, включая, например, QPixmap. Чтобы упростить демонстрацию, мы будем использовать следующее приложение-заглушку, которое обрабатывает создание нашего контейнера (QLabel ), создание растрового холста, отображение его в контейнере и добавление контейнера в главное окно.

Почему мы используем QLabel для рисования? Виджет QLabel также можно использовать для отображения изображений, и это самый простой виджет, доступный для отображения QPixmap.

Сохраните это в файл и запустите его, и вы должны увидеть следующее — одну черную линию внутри рамки окна —

Одна черная линия на холст.

Одна черная линия на холсте.

Все рисование происходит внутри метода draw_something — мы создаем экземпляр QPainter, передаем ему холст ( self.label.pixmap() ), а затем выдаем команду для рисования линии. Наконец, мы вызываем .end(), чтобы закрыть рисовальщик и применить изменения.

Обычно вам также потребуется вызвать .update() для запуска обновления виджета, но поскольку мы рисуем до того, как отображается окно приложения, обновление уже произойдет.

Рисование примитивов

QPainter предоставляет огромное количество методов для рисования фигур и линий на растровой поверхности (в версии 5.12 имеется 192 специфических для QPainter метода, не связанных с событиями). Хорошая новость заключается в том, что большинство из них являются перегруженными методами, которые представляют собой просто разные способы вызова одних и тех же базовых методов.

Например, существует 5 различных методов drawLine, каждый из которых рисует одну и ту же линию, но отличается тем, как определяются координаты того, что нужно нарисовать.

Метод Описание
drawLine(line) Нарисовать экземпляр QLine
drawLine(line) Нарисовать экземпляр QLineF
drawLine(x1, y1, x2, y2) Нарисуйте линию между x1, y2 и x2, y2 ( int )
drawLine(p1, p2 ) Нарисуйте линию между p1 и p2 (оба QPoint )
drawLine(p1, p2) Нарисуйте линию между p1 и p2 (оба QPointF )

Если вам интересно, в чем разница между QLine и QLineF , у последнего координаты указаны как float . Это удобно, если у вас есть плавающие позиции в результате других вычислений, но в остальном не очень.

Игнорируя F-варианты, у нас есть 3 уникальных способа рисования линии — с помощью линейного объекта, с двумя наборами координат (x1, y1), (x2, y2) или с двумя объектами QPoint. Когда вы обнаружите, что сама QLine определяется как QLine(const QPoint & p1, const QPoint & p2) или QLine(int x1, int y1, int x2, int y2), вы видите, что все они на самом деле одно и то же. . Различные сигнатуры вызова просто для удобства.

Учитывая координаты x1, y1, x2, y2, два объекта QPoint будут определены как QPoint(x1, y1) и QPoint(x2, y2) .

Если исключить дубликаты, у нас есть следующие операции отрисовки — drawArc, drawChord, drawConvexPolygon, drawEllipse, drawLine, drawPath, drawPie, drawPoint, drawPolygon, drawPolyline, drawRect, drawRects и drawRoundedRect. Чтобы не перегружаться, мы сначала сосредоточимся на примитивных формах и линиях и вернемся к более сложным операциям, когда разберемся с основами.

Для каждого примера замените метод draw_something в приложении-заглушке и повторно запустите его, чтобы увидеть результат.

Точка рисования

Это рисует точку или пиксель в заданной точке холста. Каждый вызов drawPoint рисует один пиксель. Замените код draw_something следующим.

Если вы повторно запустите файл, вы увидите окно, но на этот раз в его центре будет одна точка черного цвета. Вам, вероятно, придется подвигать окно, чтобы обнаружить его.

Рисование одной точки (пикселя) с помощью QPainter

Рисование одной точки (пикселя) с помощью QPainter

На самом деле особо не на что смотреть. Чтобы сделать вещи более интересными, мы можем изменить цвет и размер точки, которую мы рисуем. В PyQt цвет и толщина линий определяются с помощью активного пера в QPainter. Вы можете установить это, создав экземпляр QPen и применив его.

Это даст следующий немного более интересный результат..

Большая красная точка .

Большая красная точка.

Вы можете выполнять несколько операций рисования с помощью QPainter, пока рисование не будет завершено. Рисование на холсте происходит очень быстро — здесь мы рисуем 10 000 точек случайным образом.

Точки имеют ширину 3 пикселя и черные (перо по умолчанию).

10k 3-пиксельных точек на холст

10 тыс. 3-пиксельных точек на холсте

Часто вам может потребоваться обновить текущее перо во время рисования, например. рисовать несколько точек разными цветами, сохраняя другие характеристики (ширину) одинаковыми. Чтобы сделать это без повторного создания нового экземпляра QPen каждый раз, когда вы можете получить текущее активное перо из QPainter, используя pen = painter.pen() . Вы также можете повторно применить существующее перо несколько раз, каждый раз меняя его.

Создает следующий вывод —

Случайный шаблон из 3 точек ширины

Случайный шаблон из 3 точек шириной

В QPainter может быть активным только одно QPen — текущее перо.

Это настолько увлекательно, насколько возможно рисовать точки на экране, поэтому мы перейдем к рассмотрению некоторых других операций рисования.

нарисовать линию

В начале мы уже нарисовали линию на холсте, чтобы проверить, все ли работает. Но чего мы не пробовали, так это настроить перо для управления внешним видом линии.

В этом примере мы также используем QPoint для определения двух точек, соединяемых линией, вместо того, чтобы передавать отдельные параметры x1, y1, x2, y2 — помните, что оба метода функционально идентичны.

Толстая синяя линия

Толстая синяя линия

drawRect, drawRects и drawRoundedRect

Все эти функции рисуют прямоугольники, определяемые координатами x, y, шириной и высотой прямоугольника или экземплярами QRect или QRectF, которые предоставляют эквивалентную информацию.

Квадрат — это просто прямоугольник одинаковой ширины и высоты.

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

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

Можно также заменить несколько вызовов drawRect одним вызовом drawRects, передающим несколько объектов QRect. Это даст точно такой же результат.

Нарисованные фигуры можно заполнить в PyQt, установив текущую активную кисть для рисования brush, передав экземпляр QBrush в painter.setBrush() . В следующем примере все прямоугольники заполняются узорчатым желтым цветом.

Закрашенные прямоугольники< бр />

Закрашенные прямоугольники

Что касается пера, то для данного художника всегда активна только одна кисть, но вы можете переключаться между ними или менять их во время рисования. Доступно несколько шаблонов стиля кисти. Вы, вероятно, будете использовать Qt.SolidPattern чаще, чем любые другие.

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

Методы drawRoundedRect рисуют прямоугольник, но с закругленными краями, поэтому принимают два дополнительных параметра для x и y радиуса углов.

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

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

Существует необязательный конечный параметр для переключения между радиусами эллипса x и y углов, определяемыми в абсолютных пикселях Qt.RelativeSize (по умолчанию) или относительно размера прямоугольника (передается как значение 0…100). ). Передайте Qt.RelativeSize, чтобы включить это.

нарисоватьэллипс

Последний примитивный метод рисования, который мы сейчас рассмотрим, — это drawEllipse, который можно использовать для рисования эллипса или окружности.

Круг — это просто эллипс с одинаковой шириной и высотой.

В этом примере drawEllipse принимает 4 параметра, первые два – это координаты x и y верхнего левого угла прямоугольника, в котором будет отрисовываться эллипс, а последние два – ширина и высота этого прямоугольника соответственно.

Рисование эллипса с помощью x, у, ширина, высота или QRect.

Рисование эллипса с помощью x, y, ширины, высоты или QRect.

Вы можете добиться того же, передав QRect

Существует еще одна сигнатура вызова, которая принимает центр эллипса в качестве первого параметра, предоставляемого как объект QPoint или QPointF, а затем радиусы по осям x и y. Пример ниже показывает это в действии.

Рисование эллипса с помощью Point & радиус.

Рисование эллипса с использованием точки и радиуса.

Вы можете заполнить эллипсы, настроив QBrush так же, как и для заливки прямоугольников, доступны те же функции для стиля и цвета.

Наконец, мы совершим краткий обзор методов рисования текста в QPainter. Чтобы управлять текущим шрифтом в QPainter, вы используете передачу setFont в экземпляре QFont. При этом вы можете контролировать семейство, вес и размер (среди прочего) текста, который вы пишете. Однако цвет текста по-прежнему определяется текущим пером.

Вы также можете указать местоположение с помощью QPoint или QPointF .

Ширина пера не влияет на внешний вид текста.

Пример растрового текста привет, мир.

Пример растрового текста привет, мир.

Существуют также методы рисования текста в указанной области. Здесь параметры определяют положение x и y, а также ширину и высоту ограничивающей рамки. Текст за пределами этого поля обрезается (скрывается). Пятый параметр flags можно использовать, помимо прочего, для управления выравниванием текста внутри поля.

Ограничительная рамка обрезана рисовать текст.

Ограничивающая рамка на drawText обрезана.

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

Создание приложений с графическим интерфейсом с помощью Python и Qt6
Простой способ создания настольных приложений

Мое полное руководство, обновленное для версии 2021 и PyQt6. Все, что вам нужно для создания реальных приложений.


Загружаемая электронная книга (PDF, ePub) и полный исходный код

Для поддержки разработчиков в [[ countryRegion ]] я даю скидку [[ localizedDiscount[couponCode] ]]% с кодом [[couponCode ]] — наслаждайтесь!

Для [[ activeDiscount.description ]] я даю скидку [[ activeDiscount.discount ]]% с кодом [[КупонКод ]] — наслаждайтесь!

Немного забавы с QPainter

Это стало немного тяжело, так что давайте сделаем передышку и придумаем что-нибудь веселое. До сих пор мы программно определяли выполняемые операции отрисовки. Но мы можем так же легко рисовать в ответ на ввод пользователя — например, позволяя пользователю рисовать по всему холсту. В этой части мы возьмем то, что уже узнали, и используем его для создания простейшего приложения Paint.

Мы можем начать с той же простой схемы приложения, добавив обработчик mouseMoveEvent в класс MainWindow вместо нашего метода рисования. Здесь мы возьмем текущую позицию мыши пользователя и отобразим точку на холсте.

Почему нет события клика? Виджеты по умолчанию получают события перемещения мыши только при нажатии кнопки мыши, если не включено отслеживание мыши. Это можно настроить с помощью метода .setMouseTracking — установив для него значение True (по умолчанию False), мышь будет отслеживаться непрерывно.

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

Отрисовка отдельных точек mouseMoveEvent.

Отрисовка отдельных точек mouseMoveEvent.

Проблема здесь в том, что когда вы быстро перемещаете мышь, она на самом деле прыгает между точками на экране, а не плавно перемещается из одного места в другое. Событие mouseMoveEvent срабатывает для каждого местоположения, в котором находится мышь, но этого недостаточно для рисования непрерывной линии, если только вы не двигаетесь очень медленно.

Решение этой проблемы состоит в том, чтобы рисовать линии вместо точек. Для каждого события мы просто проводим линию от того места, где мы были (предыдущие e.x() и e.y()), до того места, где мы находимся сейчас (текущие e.x() и e.y()). Мы можем сделать это, самостоятельно отслеживая last_x и last_y.

Нам также нужно забыть последнюю позицию при отпускании мыши, иначе мы снова начнем рисовать с этого места после перемещения мыши по странице — т.е. мы не сможем прерваться линия.

Если вы запустите это, вы сможете рисовать на экране, как и ожидалось.

Рисование мышью с использованием непрерывного линия.

Рисование с помощью мыши, используя непрерывную линию.

Это все еще немного скучно, поэтому давайте добавим простую палитру, чтобы мы могли изменить цвет пера.

Для этого потребуется немного изменить архитектуру. До сих пор мы использовали mouseMoveEvent в QMainWindow. Когда у нас есть только один виджет в окне, это нормально — пока вы не измените размер окна больше, чем виджет (вы пробовали это?), координаты контейнера и единственного вложенного виджета совпадают. Однако, если мы добавим в макет другие виджеты, это не сработает — координаты QLabel будут смещены относительно окна, и мы будем рисовать в неправильном месте.

Это легко исправить, переместив управление мышью на саму метку QLabel — ее координаты события всегда относятся к ней самой. Это мы обернем как пользовательский объект Canvas, который обрабатывает создание поверхности растрового изображения, устанавливает координаты x и y и содержит текущий цвет пера (по умолчанию черный).

Этот автономный холст представляет собой вставную поверхность для рисования, которую вы можете использовать в своих собственных приложениях.

Для выбора цвета мы собираемся создать собственный виджет на основе QPushButton. Этот виджет принимает параметр цвета, который может быть экземпляром QColour, именем цвета («красный», «черный») или шестнадцатеричным значением. Этот цвет устанавливается на фоне виджета, чтобы его можно было идентифицировать. Мы можем использовать стандартный сигнал QPushButton.pressed, чтобы связать его с любыми действиями.

Определив эти две новые части, нам просто нужно выполнить итерацию по нашему списку цветов, создать кнопку QPaletteButton, передающую цвет, соединить ее сигнал нажатия с обработчиком set_pen_color на холсте (косвенно через лямбда-выражение, чтобы передать дополнительный цвет data) и добавьте его в макет палитры.

Это должно дать вам полнофункциональное многоцветное приложение для рисования, где вы можете рисовать линии на холсте и выбирать цвета из палитры.

К сожалению, это не так< бр />

К сожалению, это не делает вас хорошим художником.

Распылить

Чтобы добавить еще немного удовольствия, вы можете переключить событие mouseMoveEvent на следующее, чтобы рисовать с эффектом "аэрозольного баллончика" вместо линии. Это моделируется с помощью random.gauss для создания серии нормально распределенных точек вокруг текущей позиции мыши, которую мы наносим с помощью drawPoint .

Определите переменные SPRAY_PARTICLES и SPRAY_DIAMETER в верхней части файла и импортируйте случайный модуль стандартной библиотеки. На изображении ниже показано поведение распылителя при использовании следующих настроек:

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

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

Полнофункциональную программу для рисования, написанную с помощью PyQt5, можно найти в моем 15-минутном приложении "Piecasso".

Это введение должно было дать вам хорошее представление о том, что вы можете делать с QPainter. Как уже говорилось, эта система лежит в основе всех рисунков виджетов. Если вы хотите посмотреть дальше, ознакомьтесь с методом виджета .paint(), который получает экземпляр QPainter, чтобы позволить виджету рисовать на самом себе. Те же самые методы, которые вы здесь изучили, можно использовать в .paint() для рисования некоторых основных пользовательских виджетов. Мы расскажем об этом в следующем уроке.

Если вы нашли это руководство полезным, поделитесь им со своей сетью.
Ваша поддержка помогает мне продолжать писать эти руководства. Спасибо!

В примере Basic Drawing показано, как отображать базовые графические примитивы в различных стилях с помощью класса QPainter.

QPainter выполняет низкоуровневое рисование виджетов и других устройств рисования. Класс может рисовать все, от простых линий до сложных фигур, таких как круги и хорды. Он также может рисовать выровненный текст и растровые изображения. Обычно он рисует в «естественной» системе координат, но может дополнительно выполнять преобразование вида и мира.


В этом примере представлена ​​область рендеринга, отображающая текущую активную фигуру, и пользователь может управлять визуализируемой формой и ее внешним видом с помощью параметров QPainter. Пользователь может изменить активную фигуру (Shape) и изменить перо QPainter (Pen Ширина, стиль пера, наконечник пера, соединение пера), кисть (стиль кисти) и подсказки рендеринга (сглаживание). Кроме того, пользователь может вращать фигуру (преобразования); за кулисами мы используем способность QPainter манипулировать системой координат для выполнения поворота.

Пример Basic Drawing состоит из двух классов:

  • RenderArea – это настраиваемый виджет, который отображает несколько копий текущей активной фигуры.
  • Окно – это главное окно приложения, в котором отображается виджет RenderArea в дополнение к нескольким виджетам параметров.

Сначала мы рассмотрим класс Window, а затем рассмотрим класс RenderArea.

Определение класса окна

Класс Window наследует QWidget и представляет собой главное окно приложения, отображающее виджет RenderArea в дополнение к нескольким виджетам параметров.

Мы объявляем различные виджеты и три частных слота, обновляющих виджет RenderArea: Слот shapeChanged() обновляет виджет RenderArea, когда пользователь изменяет текущую активную фигуру. Мы вызываем слот penChanged() при изменении любого из параметров пера QPainter. А слот brushChanged() обновляет виджет RenderArea, когда пользователь меняет стиль кисти художника.

Реализация оконного класса

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

Сначала мы создаем виджет RenderArea, который будет отображать текущую активную фигуру. Затем мы создаем поле со списком Shape и добавляем связанные элементы (например, различные фигуры, которые может рисовать QPainter).

Перо QPainter — это объект QPen; класс QPen определяет, как художник должен рисовать линии и контуры фигур. У пера есть несколько свойств: ширина, стиль, колпачок и соединение.

Ширина пера может быть нулевой или больше, но чаще всего она равна нулю. Обратите внимание, что это не означает 0 пикселей, а подразумевает, что фигура рисуется максимально плавно, хотя, возможно, и некорректно с математической точки зрения.

Мы создаем QSpinBox для параметра "Ширина пера".

Стиль пера определяет тип линии. Стиль по умолчанию — сплошной (Qt::SolidLine). Установка для стиля значения none (Qt::NoPen) указывает рисовальщику не рисовать линии или контуры. Колпачок пера определяет, как рисуются конечные точки линий. И соединение пера определяет, как соединяются две линии, когда нарисовано несколько соединенных линий. Ограничение и соединение применяются только к линиям шириной от 1 пикселя.

Мы создаем QComboBox для каждого из параметров Pen Style, Pen Cap и Pen Join и добавляем связанные элементы (т. е. значения перечислений Qt::PenStyle, Qt::PenCapStyle и Qt::PenJoinStyle соответственно).< /p>

Класс QBrush определяет шаблон заливки фигур, рисуемых QPainter. Стиль кисти по умолчанию — Qt::NoBrush. Этот стиль указывает художнику не заполнять фигуры. Стандартный стиль заполнения — Qt::SolidPattern.

Мы создаем QComboBox для параметра Brush Style и добавляем связанные элементы (т. е. значения перечисления Qt::BrushStyle).

Сглаживание – это функция, которая "сглаживает" пиксели для создания более ровных и менее неровных линий. Ее можно применять с помощью подсказок рендеринга QPainter. QPainter::RenderHints используются для указания флагов QPainter, которые могут учитываться или не учитываться любым данным движком.

Мы просто создаем QCheckBox для параметра сглаживания.

Параметр «Преобразования» подразумевает манипуляции с системой координат, которые будут выглядеть так, как если бы визуализированная фигура вращалась в трех измерениях.

Мы используем функции QPainter::translate(), QPainter::rotate() и QPainter::scale() для реализации этой функции, представленной в главном окне приложения простым QCheckBox.

Затем мы соединяем виджеты параметров со связанными с ними слотами с помощью статической функции QObject::connect(), гарантируя, что виджет RenderArea обновляется всякий раз, когда пользователь изменяет форму или любые другие параметры.

Наконец, мы добавляем в макет различные виджеты и вызываем слоты shapeChanged() , penChanged() и brushChanged() для инициализации приложения. Мы также включаем сглаживание.

Слот shapeChanged() вызывается всякий раз, когда пользователь изменяет текущую активную фигуру.

Сначала мы извлекаем фигуру, выбранную пользователем, с помощью функции QComboBox::itemData(). Эта функция возвращает данные для данной роли в заданном индексе в поле со списком. Мы используем QComboBox::currentIndex() для получения индекса фигуры, а роль определяется перечислением Qt::ItemDataRole; IdRole — это псевдоним для Qt::UserRole.

Обратите внимание, что Qt::UserRole — это только первая роль, которую можно использовать для конкретных целей приложения.Если вам нужно хранить разные данные в одном и том же индексе, вы можете использовать разные роли, просто увеличивая значение Qt::UserRole, например: 'Qt::UserRole + 1' и 'Qt::UserRole + 2'. Однако хорошей практикой программирования является присвоение каждой роли собственного имени: 'myFirstRole = Qt::UserRole + 1' и 'mySecondRole = Qt::UserRole + 2'. Несмотря на то, что в этом конкретном примере нам нужна только одна роль, мы добавляем следующую строку кода в начало файла window.cpp.

Функция QComboBox::itemData() возвращает данные в виде QVariant, поэтому нам нужно преобразовать данные в RenderArea::Shape. Если данных для данной роли нет, функция возвращает QVariant::Invalid.

В конце мы вызываем слот RenderArea::setShape() для обновления виджета RenderArea.

Мы вызываем слот penChanged() всякий раз, когда пользователь изменяет любой из параметров пера. Мы снова используем функцию QComboBox::itemData() для получения параметров, а затем вызываем слот RenderArea::setPen() для обновления виджета RenderArea.

Слот brushChanged() вызывается всякий раз, когда пользователь изменяет параметр кисти, который мы извлекаем с помощью функции QComboBox::itemData(), как и раньше.

Если параметром кисти является градиентная заливка, требуются специальные действия.

Класс QGradient используется в сочетании с QBrush для определения заливки градиентом. В настоящее время Qt поддерживает три типа градиентной заливки: линейную, радиальную и коническую. Каждый из них представлен подклассом QGradient: QLinearGradient, QRadialGradient и QConicalGradient.

Поэтому, если стиль кисти Qt::LinearGradientPattern, мы сначала создаем объект QLinearGradient с областью интерполяции между координатами, переданными конструктору в качестве аргументов. Позиции задаются с использованием логических координат. Затем мы устанавливаем цвета градиента с помощью функции QGradient::setColorAt(). Цвета определяются с помощью точек остановки, которые состоят из позиции (от 0 до 1) и QColor. Набор точек остановки описывает, как должна быть заполнена область градиента. Градиент может иметь произвольное количество точек остановки.

В конце мы вызываем слот RenderArea::setBrush(), чтобы обновить кисть виджета RenderArea с помощью объекта QLinearGradient.

Подобный шаблон действий, используемый для QLinearGradient, используется в случаях Qt::RadialGradientPattern и Qt::ConicalGradientPattern.

Единственное различие заключается в аргументах, передаваемых конструктору: что касается конструктора QRadialGradient, первый аргумент — это центр, а второй — радиус радиального градиента. Третий аргумент является необязательным, но может использоваться для определения фокальной точки градиента внутри круга (фокальной точкой по умолчанию является центр круга). Что касается конструктора QConicalGradient, первый аргумент задает центр конуса, а второй задает начальный угол интерполяции.

Если стиль кисти Qt::TexturePattern, мы создаем QBrush из QPixmap. Затем мы вызываем слот RenderArea::setBrush(), чтобы обновить виджет RenderArea вновь созданной кистью.

В противном случае мы просто создаем кисть с заданным стилем и зеленым цветом, а затем вызываем слот RenderArea::setBrush(), чтобы обновить виджет RenderArea вновь созданной кистью.

Определение класса RenderArea

Класс RenderArea наследует QWidget и визуализирует несколько копий текущей активной фигуры с помощью QPainter.

Сначала мы определяем общедоступное перечисление Shape для хранения различных фигур, которые могут быть отображены виджетом (т. е. фигуры, которые могут быть отображены QPainter). Затем мы переопределяем конструктор, а также две общедоступные функции QWidget: MinimumSizeHint() и sizeHint().

Мы также повторно реализуем функцию QWidget::paintEvent(), чтобы иметь возможность рисовать текущую активную фигуру в соответствии с указанными параметрами.

Мы объявляем несколько закрытых слотов: слот setShape() изменяет форму RenderArea, слоты setPen() и setBrush() изменяют перо и кисть виджета, а слоты setAntialiased() и setTransformed() изменяют форму виджета. соответствующие свойства.

Реализация класса RenderArea

В конструкторе мы инициализируем некоторые переменные виджета.

Мы устанавливаем его форму как многоугольник, его свойство сглаживания — как false, и мы загружаем изображение в переменную растрового изображения виджета. В конце мы устанавливаем роль фона виджета, определяя кисть из палитры виджета, которая будет использоваться для рендеринга фона. QPalette::Base обычно белого цвета.

RenderArea наследует свойство QWidget sizeHint, содержащее рекомендуемый размер виджета. Если значение этого свойства имеет недопустимый размер, размер не рекомендуется.

Реализация по умолчанию функции QWidget::sizeHint() возвращает недопустимый размер, если для виджета нет макета, и возвращает предпочтительный размер макета в противном случае.

Наша повторная реализация функции возвращает QSize с шириной 400 пикселей и высотой 200 пикселей.

RenderArea также наследует свойство QWidget's minimumSizeHint, содержащее рекомендуемый минимальный размер виджета. Опять же, если значение этого свойства имеет недопустимый размер, размер не рекомендуется.

Реализация QWidget::minimumSizeHint() по умолчанию возвращает недопустимый размер, если для виджета нет макета, и возвращает минимальный размер макета в противном случае.

Наша новая реализация функции возвращает QSize с шириной 100 пикселей и высотой 100 пикселей.

Общедоступные слоты setShape() , setPen() и setBrush() вызываются всякий раз, когда мы хотим изменить форму, перо или кисть виджета RenderArea. Мы устанавливаем форму, перо или кисть в соответствии с параметром слота и вызываем QWidget::update(), чтобы сделать изменения видимыми в виджете RenderArea.

Слот QWidget::update() не вызывает немедленную перерисовку; вместо этого он планирует обработку события рисования, когда Qt возвращается в основной цикл обработки событий.

С помощью слотов setAntialiased() и setTransformed() мы изменяем состояние свойств в соответствии с параметром слота и вызываем слот QWidget::update(), чтобы сделать изменения видимыми в виджете RenderArea.

Затем мы повторно реализуем функцию QWidget::paintEvent(). Первое, что мы делаем, это создаем графические объекты, которые нам понадобятся для рисования различных фигур.

Мы создаем вектор из четырех QPoints. Мы используем этот вектор для рендеринга фигур Points, Polyline и Polygon. Затем мы создаем QRect, определяя прямоугольник на плоскости, который мы используем в качестве ограничивающего прямоугольника для всех фигур, кроме контура и растрового изображения.

Мы также создаем QPainterPath. Класс QPainterPath предоставляет контейнер для операций рисования, позволяющий создавать и повторно использовать графические фигуры. Путь художника — это объект, состоящий из ряда графических строительных блоков, таких как прямоугольники, эллипсы, линии и кривые. Для получения дополнительной информации о классе QPainterPath см. пример Painter Paths. В этом примере мы создаем путь художника, состоящий из одной прямой линии и кривой Безье.

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

Мы создаем QPainter для виджета RenderArea и устанавливаем перо и кисть рисовальщика в соответствии с пером и кистью RenderArea. Если отмечена опция параметра Antialiasing, мы также устанавливаем подсказки рендеринга рисовальщика. QPainter::Antialiasing указывает, что движок должен сглаживать края примитивов, если это возможно.

Наконец, мы визуализируем несколько копий формы RenderArea . Количество копий зависит от размера виджета RenderArea, и мы вычисляем их положение, используя два цикла for и высоту и ширину виджета.

Для каждой копии мы сначала сохраняем текущее состояние рисовальщика (помещаем состояние в стек). Затем мы переводим систему координат с помощью функции QPainter::translate() в положение, определяемое переменными цикла for. Если мы опустим этот перевод системы координат, все копии фигуры будут отображаться друг над другом в левом верхнем углу виджета RenderArea.

Если отмечена опция параметра Transformations, мы делаем дополнительное перемещение системы координат, прежде чем повернуть систему координат на 60 градусов по часовой стрелке с помощью функции QPainter::rotate(), и уменьшить ее размер с помощью QPainter::scale () функция. В конце мы переводим систему координат обратно туда, где она была до поворота и масштабирования.

Теперь при рендеринге фигура будет выглядеть так, как если бы она была повернута в трех измерениях.

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

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

Затем, когда мы закончим рендеринг копии фигуры, мы можем восстановить исходное состояние рисовальщика с соответствующей системой координат, используя функцию QPainter::restore(). Таким образом мы гарантируем, что следующая копия фигуры будет отображена в правильном положении.

Мы могли бы перевести систему координат обратно с помощью QPainter::translate() вместо сохранения состояния рисовальщика. Но так как мы помимо переноса системы координат (когда отмечена опция параметра Transformation) и вращаем, и масштабируем систему координат, самым простым решением является сохранение текущего состояния рисовальщика.

© 2022 The Qt Company Ltd. Права на документацию, включенную в настоящий документ, принадлежат их соответствующим владельцам.Предоставленная здесь документация распространяется под лицензией GNU Free Documentation License версии 1.3, опубликованной Free Software Foundation. Qt и соответствующие логотипы являются товарными знаками The Qt Company Ltd. в Финляндии и/или других странах мира. Все остальные товарные знаки являются собственностью соответствующих владельцев.

В этой части руководства по программированию на Qt5 C++ мы немного порисуем.

Класс QPainter полезен, когда мы рисуем в Qt5. Рисование выполняется классом QPainter в ответ на метод paintEvent.

Линии

В первом примере мы нарисуем несколько линий в клиентской области окна.

Это заголовочный файл.

Рисуем на окне шесть линий; каждая линия имеет свой стиль пера.

PaintEvent вызывается при обновлении виджета. Здесь мы создаем объект QPainter и рисуем. Поскольку мы не используем объект QPaintEvent, мы отключаем предупреждение компилятора с помощью макроса Q_UNUSED. Реальное рисование делегируется методу drawLines.

Мы создаем объект QPen. Перо сплошное, толщиной 2 пикселя, черного цвета. Перо используется для рисования линий и контуров фигур. Перо устанавливается в объект рисования с помощью метода setPen.

Метод drawLine рисует линию. Четыре параметра являются координатами двух точек в окне.

Метод setStyle строки QPen задает стиль пера — Qt::DashLine .

Это основной файл.

Цвета

Цвет — это объект, представляющий комбинацию значений интенсивности красного, зеленого и синего (RGB) цветов. Допустимые значения RGB находятся в диапазоне от 0 до 255. В следующем примере мы рисуем девять прямоугольников, заполненных девятью разными цветами.

Это заголовочный файл.

Мы рисуем девять прямоугольников с заливкой разным цветом. Контур прямоугольников серый.

Класс QBrush определяет шаблон заливки фигур, нарисованных с помощью QPainter. Метод drawRect рисует прямоугольник. Он рисует прямоугольник с левым верхним углом в точке x, y и с заданными шириной и высотой. Мы использовали шестнадцатеричное представление для указания значения цвета.

Это основной файл.

Шаблоны

Следующий пример программного кода аналогичен предыдущему. На этот раз мы заполняем прямоугольники различными предопределенными узорами.

Это заголовочный файл.

Мы рисуем девять прямоугольников различными узорами кисти.

Мы рисуем прямоугольник по определенному шаблону. Qt::HorPattern — это константа, используемая для создания шаблона горизонтальных линий.

Это основной файл.

Прозрачные прямоугольники

Прозрачность – это способность видеть сквозь материал. Самый простой способ понять прозрачность — представить себе кусок стекла или воды. Технически лучи света могут проходить сквозь стекло, и таким образом мы можем видеть объекты за стеклом.

В компьютерной графике мы можем добиться эффекта прозрачности, используя альфа-композитинг. Альфа-композитинг — это процесс объединения изображения с фоном для создания эффекта частичной прозрачности. В процессе композиции используется альфа-канал.

Это заголовочный файл.

В примере показано десять прямоугольников с разными уровнями прозрачности.

Метод setOpacity устанавливает непрозрачность рисовальщика. Значение должно находиться в диапазоне от 0,0 до 1,0, где 0,0 — полностью прозрачный, а 1,0 — полностью непрозрачный.

Это основной файл.

Пончик

В следующем примере мы создадим форму пончика.

Это заголовочный файл.

"Пончик" – это усовершенствованная геометрическая форма, напоминающая такую ​​еду. Мы создаем его, рисуя 72 повернутых эллипса.

Мы будем рисовать в режиме сглаживания. Рендеринг будет более высокого качества.

Эти линии перемещают начало системы координат в середину окна. По умолчанию он расположен в точке 0, 0. Другими словами, в верхнем левом углу окна. Переместив систему координат, рисовать будет намного проще.

В этом цикле for мы рисуем 72 повернутых эллипса.

Это основной файл.

Фигуры

API рисования Qt5 может рисовать различные фигуры. В следующем примере программного кода показаны некоторые из них.

Это заголовочный файл.

Мы рисуем девять разных фигур.

QPainterPath — это объект, используемый для создания сложных фигур. Мы используем его для рисования кривых Безье.

Эти строки кода рисуют круговую диаграмму, хорду и прямоугольник со скругленными углами.

Здесь мы рисуем многоугольник с помощью метода drawPolygon. Многоугольник состоит из пяти точек.

Qt5 позволяет создать путь на основе символа шрифта.

drawEllipse также рисует эллипс и окружность. Окружность является частным случаем эллипса. Параметрами являются координаты x и y начала прямоугольника, а также ширина и высота ограничивающего прямоугольника эллипса.

Это основной файл примера.

Градиенты

В компьютерной графике градиент – это плавное смешение оттенков от светлого к темному или от одного цвета к другому. В программах для 2D-рисования и рисования градиенты используются для создания красочных фонов и специальных эффектов, а также для имитации света и теней.

В следующем примере кода показано, как создавать линейные градиенты.

Это заголовочный файл.

В примере кода мы рисуем два прямоугольника и заливаем их линейными градиентами.

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

Цвета в градиенте определяются с помощью точек остановки. setColorAt создает точку остановки в данной позиции с заданным цветом.

Мы заполняем прямоугольник градиентом.

Это основной файл.

Радиальный градиент

Радиальные градиенты – это смешение цветов или оттенков цветов между двумя кругами.

Это заголовочный файл.

В примере создается радиальный градиент; градиент распространяется от центра окна.

QRadialGradient создает радиальный градиент; он интерполирует цвета между фокальной точкой и конечными точками окружающего ее круга. Параметрами являются координаты центральной точки окружности и ее радиус. Фокус находится в центре круга.

Метод setColorAt определяет цветные точки.

Вся область окна заполнена радиальным градиентом.

Это основной файл.

В последнем примере этой главы руководства по C++ Qt5 мы создаем эффект затяжки. В примере отображается растущий центрированный текст, который постепенно исчезает в какой-то момент. Это очень распространенный эффект, который часто можно увидеть во флеш-анимациях в Интернете.

В заголовочном файле определены два обработчика событий: обработчик события рисования и обработчик таймера.

Это файл puff.cpp.

В конструкторе мы запускаем таймер. Каждые 15 мс генерируется событие таймера.

Внутри timerEvent мы увеличиваем размер шрифта и перерисовываем виджет.

Если размер шрифта больше 10 пунктов, мы постепенно уменьшаем непрозрачность; текст начинает исчезать.

Существует так много возможностей Python для разработки приложений с графическим интерфейсом, и PyQt5 — одна из них. PyQt5 — это кроссплатформенный инструментарий с графическим интерфейсом, набор привязок Python для Qt v5. Благодаря инструментам и простоте, предоставляемым этой библиотекой, можно с легкостью разработать интерактивное настольное приложение.

В этой статье мы увидим, как создать приложение Paint с помощью PyQt5. Наше приложение Paint будет состоять из следующего

  1. Пользователь может выбирать разные размеры кисти.
  2. Пользователь может выбрать другой цвет кисти.
  3. Сохранение холста
  4. Очистка всего холста сразу


Этапы создания виджетов –
1. Создайте окно, задайте его геометрию и заголовок
2. Создать строку меню
3. Внутри строки меню добавьте различные меню, а именно меню файла, меню размера и меню цвета
4. Добавить действие сохранения и очистки в меню файлов

5. Добавьте действие с различными размерами кисти в меню размера кисти

6. Добавьте различные действия с цветом кисти в меню цвета кисти

7. Создайте белый холст и добавьте его в окно

Внутренние этапы:
1. Создайте другую переменную: флаг рисования, чтобы проверить, рисует ли он в данный момент или нет, и установите для него значение False, переменная размера кисти, чтобы установить текущий размер кисти, цвет кисти, чтобы установить текущий цвет кисти, и переменная текущего положения, чтобы знать положение курсора
2. Добавьте действие в виджет очистки и сохранения
3. Внутри четкого действия заливаем холст белым цветом
4. Внутри действия сохранения сохраните холст
5. Добавьте действия (методы) к различным размерам кисти и цвету, чтобы установить размер и цвет
6. Создайте событие рисования для рисования белого холста на экране
7. Создайте метод, чтобы знать, когда левая кнопка мыши нажата внутри этого метода, установите флажок рисования и измените текущую позицию
8. Создайте метод для движения мыши, внутри этого метода проверьте, установлен ли флажок рисования и кнопка все еще нажата, затем нарисуйте с помощью объекта рисования и измените положение в соответствии с ним.
9. Создайте метод, чтобы знать, что кнопка мыши отпущена внутри этого метода, установите флаг рисования в false.

Читайте также: