Evgenii Legotckoi
Evgenii Legotckoi24. September 2015 10:56

Qt/C++ - Lektion 021. Die Zeichenmaus in Qt

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

Video-Tutorial zum Zeichnen in Qt

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

Р
  • 25. August 2017 04:00

Здравствуйте! Спасибо за подробное описание данного примера, а вы бы не могли показать, что все это время происходило в main.cpp?
Потому что при использовании данного примера я получила ошибку:

321: ошибка: 'addLine' was not declared in this scope
QPen(Qt::red,10,Qt::SolidLine));
^
И я просто не могу понять, что же не так?

Evgenii Legotckoi
  • 25. August 2017 04:20

Добрый день!
main.cpp остаётся созданным по умолчанию, там ничего интересного для Вас нет.
А ошибка говорит о том, что у Вас отсутствует необходимый заголовочный файл, вернее его подключение.

Думаю, что Вы пропустили следующий include

#include <QGraphicsScene>
Р
  • 25. August 2017 06:04

Нет, не пропустила, есть инклюд
Полагаю, ошибка в вызове в главном окне этой сцены.
Или в чем-то еще, ибо он не заходит в эту библиотеку и соотвественно не видит addline

Evgenii Legotckoi
  • 25. August 2017 06:25

то есть вызываете этот метод так?

void mainWindow::someMethod()
{
    graphicsScene->addLine();
}
Вообще такая ошибка говорит о том, что метод или функция не объявлены, а это значит зачастую, что пропущен необходимый инклюд.
a
  • 11. Mai 2018 02:28

А почему mouseMoveEvent() выполняется лишь при на нажатой кнопки мыши?

По сигнатуре функции я предположил, что метод должен вызываться сценой при простом движением мышки по сцене.
Evgenii Legotckoi
  • 11. Mai 2018 03:10

Чтобы включить такое поведение, необходимо вызвать метод setMouseTracking(true) у QGraphicsView, в котором расположена графическая сцена, тогда события движения мыши должны передаваться при движении курсора как с нажатыми клавишами мыши, так и без.


Paint::Paint(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Paint)
{
    ui->setupUi(this);
 
    scene = new paintScene();       
    ui->graphicsView->setScene(scene);  
    ui->graphicsView->setMouseTracking(true);
 
}
a
  • 11. Mai 2018 03:56

Спасибо, попробовал. Работает )

Михаиллл
  • 10. Juni 2019 02:43
  • (bearbeitet)

Я задал в конструкторе Paint картинку на лэйбел. Скажите пожалуйста, как рисовать на mapImage.

    QImage mapImage("C:\\Users\\New Owner\\Downloads\\mapMain.png");
    ui->label->setPixmap(QPixmap::fromImage(mapImage,Qt::AutoColor));

и я унаследовал клас рисовальщик так, но в нем нет таких сигналов, какие используется в .срр:

class paintScene : public QLabel
Evgenii Legotckoi
  • 10. Juni 2019 03:52

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

И естественно, что там не будет тех сигналов и методов, потому что PaintScene нужно наследовать от QGraphicsScene. Рисовать нужно на графической сцене.

ИВ
  • 28. April 2020 17:12

Добрый день. Извините за нюбский вопрос.
Данный проект у меня работает, что вызвало удивление. Так как я не нашел слотов, принимающих события от void mousePressEvent(QGraphicsSceneMouseEvent * event); и void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
Я пока разбираюсь со слотами, обьясните пожалуйста - выходит если сигнал (в данном случае событие) описан внутри класса, то для обьектов класса слот не нужен ?

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

f
  • 9. Oktober 2022 18:40
  • (bearbeitet)

Здравствуйте! Не понимаю в чем проблема, ui(new Ui::Paint) обозначается как недопустимый неполный тип и программа не запускается. Уже скопировал тупо только ваш код без собственных фрагментов, но все та же проблема. Помогите пожалуйста, срочно! Программирую в среде Visual Studio 2019.

upd: все исправил

J
  • 30. März 2023 11:57

Евгений, здравствуйте! Только начал изучение Qt и возник вопрос по 21ому уроку. После написания кода, выдаёт следующие ошибки

В чём может быть проблема?

Evgenii Legotckoi
  • 16. April 2023 04:03

В UI файле не был добавлен QGraphicsView объект с object name graphicsView

J
  • 19. April 2023 05:18
  • (bearbeitet)

Евгений, исправил: благодарю! Всё работает!

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
A
ALO1ZE19. Oktober 2024 08:19
Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken