Und in dieser Lektion werden wir das Zeichnen mit einer Maus in Qt basierend auf dem primitivsten Analogon von Paint mit QGraphicsScene meistern. Keine Anpassungen, keine Pinselgrößen, keine Palette, keine Spezialeffekte, nur eine rote Linie, die wir mit der Maus zeichnen.
Die Aufgabe ist gesetzt - weiter zur Ausführung!
Projektstruktur
Projektstruktur Die Projektstruktur umfasst folgende Dateien:
- paint.h - die Header-Datei des Widgets, in der sich die Grafikszene zum Zeichnen befindet;
- paint.cpp - bzw. die Quellcodedatei für dieses Widget;
- paintscene.h - Header-Datei der benutzerdefinierten Grafikszene, mit der wir arbeiten werden;
- paintscene.cpp - Quellcodedatei für eine benutzerdefinierte Grafikszene.
paint.ui
Die Form des Hauptanwendungsfensters besteht aus dem Widget selbst und dem darin platzierten QGraphicsView Objekt.
malen.h
Diese Datei deklariert eine benutzerdefinierte Grafikszene sowie einen Timer mit einem Slot für diesen Timer, der verwendet wird, um die Größenänderung des Anwendungsfensters korrekt zu handhaben.
#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
In dieser Klasse wird einem Objekt der Klasse QGraphicsView eine angepasste Grafikszene hinzugefügt; tatsächlich hat der Programmcode aus diesem Teil des Beispiels zu Trainingszwecken keinen besonderen Bezug zum Zeichenprozess selbst, aber der Vollständigkeit halber ist in diesem Beispiel die Praxis der Größenänderung des Fensters enthalten. Das Zeichnen selbst erfolgt ausschließlich in der angepassten Grafikszene.
#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
Und hier ist die Header-Datei des Täters für dieses Beispiel. Das Zeichnen erfolgt mit Linien, indem das Ereignis mouseMoveEvent behandelt wird. Dazu wird die Funktion mouseMoveEvent neu definiert, in der in zwei Koordinaten die erste aus dem vergangenen Ereignis und die zweite aus dem aktuellen, rot Linien werden gezeichnet, die schließlich eine gemeinsame Kurve bilden. Damit wir aber beim Loslassen und erneuten Drücken der Maustaste eine neue Linie ziehen können und nicht mit der alten fortfahren, überschreiben wir die Funktion mousePressEvent. .
Das mousePressEvent zeichnet eine Ellipse, die als Ausgangspunkt für die gekrümmte Maus dient. Diese Methode aktualisiert die ersten Koordinatenwerte für die erste Linie, wodurch die alte Kurve von der neuen unterbrochen und getrennt wird. Das Video-Tutorial demonstriert dies. Der erste Koordinatenpunkt für die Linie wird in previousPoint gespeichert.
#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
In dieser Datei finden alle Zeichenarbeiten in den Methoden mouseMoveEvent und mousePressEvent. statt, während im Klassenkonstruktor keine Initialisierung stattfindet.
#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(); }
Ergebnis
Als Ergebnis können Sie rote Linien in die Grafikszene ziehen und diese Fähigkeiten weiterentwickeln - es hängt bereits von Ihnen ab.
Sie können die Kommentare und eine Demonstration des Projekts auch im Video-Tutorial zu diesem Artikel lesen.
Zeichnen im Quellcode-Archiv des Qt-Projekts: 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
Евгений, исправил: благодарю! Всё работает!