А в этом уроке освоим рисование мышью в Qt на основе примитивнейшего аналога Paint с использованием QGraphicsScene . Никаких регулировок, ни размеров кисти, ни палитры, ни спецэффектов, а просто красная линия, которую мы будем рисовать мышью.
Задача поставлена - вперёд исполнять!
Структура проекта
Структура проекта В структуру проекта входят следующие файлы:
- paint.h - заголовочный файл виджета, в котором будет располагаться графическая сцена для рисования;
- paint.cpp - соответственно файл исходных кодов для этого виджета;
- paintscene.h - заголовочный файл кастомизированной графической сцены, с которой мы будем работать;
- paintscene.cpp - файл исходных кодов кастомизированной графической сцены.
paint.ui
Форма главного окна приложения состоит из самого виджета и помещенного в него объекта QGraphicsView.
paint.h
В данном файле объявляется кастомизированная графическая сцена, а также таймер со слотом для этого таймера, который служит для корректной обработки изменения размеров окна приложения.
#ifndef PAINT_H #define PAINT_H #include <QWidget> #include <QTimer> #include <QResizeEvent> #include <paintscene.h> namespace Ui { class Paint; } class Paint : public QWidget { Q_OBJECT public: explicit Paint(QWidget *parent = 0); ~Paint(); private: Ui::Paint *ui; QTimer *timer; /* Определяем таймер для подготовки актуальных размеров * графической сцены * */ paintScene *scene; // Объявляем кастомную графическую сцену private: /* Переопределяем событие изменения размера окна * для пересчёта размеров графической сцены * */ void resizeEvent(QResizeEvent * event); private slots: void slotTimer(); }; #endif // PAINT_H
paint.cpp
В данном классе происходит добавление кастомизированной графической сцены в объект класса QGraphicsView , фактически в целях обучения программный код из данной части примера не имеет особого отношения к самому процессу рисования, но отработка изменения размеров окна включена в данный пример для полноты картины. Само рисование происходит исключительно в кастомизированной графической сцене.
#include "paint.h" #include "ui_paint.h" Paint::Paint(QWidget *parent) : QWidget(parent), ui(new Ui::Paint) { ui->setupUi(this); scene = new paintScene(); // Инициализируем графическую сцену ui->graphicsView->setScene(scene); // Устанавливаем графическую сцену timer = new QTimer(); // Инициализируем таймер connect(timer, &QTimer::timeout, this, &Paint::slotTimer); timer->start(100); // Запускаем таймер } Paint::~Paint() { delete ui; } void Paint::slotTimer() { /* Переопределяем размеры графической сцены в зависимости * от размеров окна * */ timer->stop(); scene->setSceneRect(0,0, ui->graphicsView->width() - 20, ui->graphicsView->height() - 20); } void Paint::resizeEvent(QResizeEvent *event) { timer->start(100); QWidget::resizeEvent(event); }
paintscene.h
А вот и заголовочный файл виновника данного примера. Рисование происходит с помощью линий, посредством обработки события mouseMoveEvent. Для этого переопределяется функция mouseMoveEvent в которой по двум координатам, первая от прошлого события и вторая от текущего, строятся красные линии, которые в итоге образуют общую кривую. Но чтобы при отпускании кнопки мыши и повторном нажатии мы могли рисовать новую линию, а не продолжать старую, переопределяем функцию mousePressEvent.
В mousePressEvent отрисовывается эллипс, который служит стартовой точкой рисования кривой мышью. Этот метод обновляет значения первой координаты для первой линии, таким образом разрывая и отделяя старую кривую от новой. В видеоуроке это продемонстрировано. Точка первой координаты для линии сохраняется в объект previousPoint.
#ifndef PAINTSCENE_H #define PAINTSCENE_H #include <QGraphicsScene> #include <QGraphicsSceneMouseEvent> #include <QTimer> #include <QDebug> class paintScene : public QGraphicsScene { Q_OBJECT public: explicit paintScene(QObject *parent = 0); ~paintScene(); private: QPointF previousPoint; // Координаты предыдущей точки private: // Для рисования используем события мыши void mousePressEvent(QGraphicsSceneMouseEvent * event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); }; #endif // PAINTSCENE_H
paintscene.cpp
В данном файле вся работа с рисованием происходит в методах mouseMoveEvent и mousePressEvent. Тогда как в конструкторе класса вообще не происходит какой-либо инициализации.
#include "paintscene.h" paintScene::paintScene(QObject *parent) : QGraphicsScene(parent) { } paintScene::~paintScene() { } void paintScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { // При нажатии кнопки мыши отрисовываем эллипс addEllipse(event->scenePos().x() - 5, event->scenePos().y() - 5, 10, 10, QPen(Qt::NoPen), QBrush(Qt::red)); // Сохраняем координаты точки нажатия previousPoint = event->scenePos(); } void paintScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { // Отрисовываем линии с использованием предыдущей координаты addLine(previousPoint.x(), previousPoint.y(), event->scenePos().x(), event->scenePos().y(), QPen(Qt::red,10,Qt::SolidLine,Qt::RoundCap)); // Обновляем данные о предыдущей координате previousPoint = event->scenePos(); }
Итог
В результате Вы сможете рисовать на графической сцене красные линии, а как дальше уже развить эти возможности - это уже зависит от Вас.
Также вы можете ознакомиться с комментариями и демонстрацией проекта в видеоуроке по данной статье.
Рисование в Qt Архив с исходным кодом проекта: Qt paint
Здравствуйте! Спасибо за подробное описание данного примера, а вы бы не могли показать, что все это время происходило в main.cpp?
Потому что при использовании данного примера я получила ошибку:
321: ошибка: 'addLine' was not declared in this scope
QPen(Qt::red,10,Qt::SolidLine));
^
И я просто не могу понять, что же не так?
Добрый день!
main.cpp остаётся созданным по умолчанию, там ничего интересного для Вас нет.
А ошибка говорит о том, что у Вас отсутствует необходимый заголовочный файл, вернее его подключение.
Думаю, что Вы пропустили следующий include
Нет, не пропустила, есть инклюд
Полагаю, ошибка в вызове в главном окне этой сцены.
Или в чем-то еще, ибо он не заходит в эту библиотеку и соотвественно не видит addline
то есть вызываете этот метод так?
Вообще такая ошибка говорит о том, что метод или функция не объявлены, а это значит зачастую, что пропущен необходимый инклюд.А почему mouseMoveEvent() выполняется лишь при на нажатой кнопки мыши?
Чтобы включить такое поведение, необходимо вызвать метод setMouseTracking(true) у QGraphicsView, в котором расположена графическая сцена, тогда события движения мыши должны передаваться при движении курсора как с нажатыми клавишами мыши, так и без.
Спасибо, попробовал. Работает )
Я задал в конструкторе Paint картинку на лэйбел. Скажите пожалуйста, как рисовать на mapImage.
и я унаследовал клас рисовальщик так, но в нем нет таких сигналов, какие используется в .срр:
Вообще не понимаю, зачем вы используете QLabel для этого. Используйте графическую сцену и рисуйте на ней. QLabel был написан для отображения текста и картинок, но никак не для рисования.
И естественно, что там не будет тех сигналов и методов, потому что PaintScene нужно наследовать от QGraphicsScene. Рисовать нужно на графической сцене.
Добрый день. Извините за нюбский вопрос.
Данный проект у меня работает, что вызвало удивление. Так как я не нашел слотов, принимающих события от void mousePressEvent(QGraphicsSceneMouseEvent * event); и void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
Я пока разбираюсь со слотами, обьясните пожалуйста - выходит если сигнал (в данном случае событие) описан внутри класса, то для обьектов класса слот не нужен ?
Добрый день. Это переопределённые методы из базового класса, они не являются слотами и вызываются в очереди событий внутри ядра Qt фреймворка. В обычном программировании на Qt никто не ищет откуда они конкретно вызываются. Для этого нужно копаться в исходниках Qt. То есть сигнала нет внутри класса и сигналы нужны для слотов, но в данном конкретном случае к вызову этих методов обобщённо говоря сигналы отношения не имеют.
Здравствуйте! Не понимаю в чем проблема, ui(new Ui::Paint) обозначается как недопустимый неполный тип и программа не запускается. Уже скопировал тупо только ваш код без собственных фрагментов, но все та же проблема. Помогите пожалуйста, срочно! Программирую в среде Visual Studio 2019.
upd: все исправил
Евгений, здравствуйте! Только начал изучение Qt и возник вопрос по 21ому уроку. После написания кода, выдаёт следующие ошибки
В чём может быть проблема?
В UI файле не был добавлен QGraphicsView объект с object name graphicsView
Евгений, исправил: благодарю! Всё работает!