Evgenii Legotckoi
Evgenii Legotckoi17 сентября 2015 г. 10:22

Qt/C++ - Урок 019. Рисуем треугольник в Qt5. Позиционирование в QGraphicsScene

Рисование интерфейсов, формирование таблиц баз данных, работа с сетью - это всё хорошо, но иногда хочется просто, что-нибудь нарисовать, например треугольник . А потом конечно же оживить этот объект, чтобы им можно было управлять, и в последствии превратить этот проект в маленькую игру. Ну кто не хочет написать собственную игру, даже самую простую?

Давайте тогда сделаем первый шаг в сторону простенькой игры, а именно разберемся с рисованием объектов в Qt, попробовав нарисовать треугольник .

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

Структура проекта "Треугольник"

Опишем структуру проекта, в котором будем рисовать треугольник:

  • Triangle.pro - профайл проекта, создается по умолчанию и в данном проекте не требует корректироваки;
  • main.cpp - файл, с которого стартует приложение, в данном файле вызывается widget, в котором будет располагаться графическая сцена с треугольником;
  • widget.h - заголовочный файл, вызываемого виджета с графической сценой;
  • widget.cpp - файл исходных кодов виджета;
  • triangle.h - заголовочный файл класса Треугольника , который наследован от QGraphicsItem;
  • triangle.cpp - файл исходных кодов класса Треугольник.

mainwindow.ui

В дизайнере интерфейсов просто закидываем QGraphicsView в виджет. Больше ничего не требуется.

widget.h

В данном файле всего лишь объявляем графическую сцену и объект треугольника, с которым будем работать.

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QGraphicsScene>

#include <triangle.h>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget      *ui;
    QGraphicsScene  *scene;     // Объявляем графическую сцену 
    Triangle        *triangle;  // и треугольник
};

#endif // WIDGET_H

widget.cpp

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

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(600,600);          // Задаем размеры виджета, то есть окна
    this->setFixedSize(600,600);    // Фиксируем размеры виджета

    scene = new QGraphicsScene();   // Инициализируем графическую сцену
    triangle = new Triangle();      // Инициализируем треугольник

    ui->graphicsView->setScene(scene);  // Устанавливаем графическую сцену в graphicsView
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);    // Устанавливаем сглаживание
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по горизонтали

    scene->setSceneRect(-250,-250,500,500); // Устанавливаем область графической сцены

    scene->addLine(-250,0,250,0,QPen(Qt::black));   // Добавляем горизонтальную линию через центр
    scene->addLine(0,-250,0,250,QPen(Qt::black));   // Добавляем вертикальную линию через центр

    scene->addItem(triangle);   // Добавляем на сцену треугольник
    triangle->setPos(0,0);      // Устанавливаем треугольник в центр сцены


}

Widget::~Widget()
{
    delete ui;
}

triangle.h

А вот теперь настало время проработать сам класс, в котором создаётся треугольник. В данном случае наследуемся от QGraphicsItem .

#ifndef TRIANGLE_H
#define TRIANGLE_H

#include <QGraphicsItem>
#include <QPainter>

// Наследуемся от QGraphicsItem
class Triangle : public QGraphicsItem
{
public:
    Triangle();
    ~Triangle();

protected:
    QRectF boundingRect() const;    /* Определяем виртуальный метод,
                                     * который возвращает область, в которой
                                     * находится треугольник
                                     * */
    /* Определяем метод для отрисовки треугольника
     * */
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};

#endif // TRIANGLE_H

triangle.cpp

А теперь рисуем треугольник в нашем классе. Здесь имеется один важный момент. Координатная система объекта QGraphicsItem - это понятие отличное от координатной системы графической сцены. То есть каждый объект QGraphicsItem или унаследованный от данного класса имеет свою собственную систему координат, которая транслируется в систему координат QGraphicsScene . Когда мы задаём позицию, где будет находиться объект на графической сцене, то мы указываем, где будет находится точка графического объекта, которая имеет координаты 0 по оси X и 0 по оси Y, в координатной системе объекта, поэтому важно, чтобы данная точка была в центре графического объекта. Это упростит дальнейшую работу, если конечно вы осознанно не предполагаете иного варианта.

#include "triangle.h"

Triangle::Triangle() :
    QGraphicsItem()
{

}

Triangle::~Triangle()
{

}

QRectF Triangle::boundingRect() const
{
    return QRectF(-25,-40,50,80);   // Ограничиваем область, в которой лежит треугольник
}

void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
        QPolygon polygon;   // Используем класс полигона, чтобы отрисовать треугольник
        // Помещаем координаты точек в полигональную модель
        polygon << QPoint(0,-40) << QPoint(25,40) << QPoint(-25,40);
        painter->setBrush(Qt::red);     // Устанавливаем кисть, которой будем отрисовывать объект
        painter->drawPolygon(polygon);  // Рисуем треугольник по полигональной модели
        Q_UNUSED(option);
        Q_UNUSED(widget);
}

Итог

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

Также рекомендую ознакомиться с видеоуроком, в котором подробнее рассмотрен момент с установкой координат графического объекта.

Архив с проектом

Видеоурок

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

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

J
  • 8 июня 2023 г. 12:14
  • (ред.)

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

Справа мы видим координаты graphicView

Дальше берём сам код:

this->resize(10000,10000);          // Задаем размеры виджета, то есть окна
this->setFixedSize(460,380);    // Фиксируем размеры виджета

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

Получается вот так:
1 -это сам виджет, 2 - это наш слой. И оба они имеют свои размеры как на предыдущей картинке.

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

    scene->setSceneRect(-250,-250,700,700); // Устанавливаем область графической сцены

    map->setPos(0,0);      // Устанавливаем квадрат в центр сцены

Далее вот эти строчки:
Изменяя размеры в scene->setSceneRect(), визуально ничего не меняется. Почему?
Это и есть установка размеров области нашего QGraphicsView? Если да- то что за размеры остаются в ui-файле при этом?

Далее, я пытаюсь отрисовать квадрат в классе Map, но он не появляется на сцене, хотя когда я делал на координатах вашего урока, он был. Но как только я начал изменять их, он исчез. И тут я задумался собственно. Я хотел нарисовать квадрат ровно в левом углу сцены, которая имеет координаты (-250,-250), но квадрат так и не появлялся. Только когда я ставил координаты где-то ориенитирочно(-130,-130), то он вставал как раз в левый угол


Еще, я так и не понял что делает функция

QRectF Map::boundingRect() const
{
    return QRectF(0,0,60,60);   // Ограничиваем область, в которой лежит прямоугольник
}

Что именно она ограничивает? Думал, что за границы, которые определяет этот метод, нельзя "выйти", т.е, отрисовать квадрат "ЗА" установленными этим методом координатами, но это не так!
В итоге решил поиграться с координатами в графическом файлу ui и квадрат после этого совсем исчез.
Подскажите, что я делаю не так? В чём моя основная ошибка? Может где-то можно об этом почитать поподробнее? Я помню ваши слова, что координаты QGraphicsScene и QGraphicsItem разные, но я всё равно не понимаю как автоматически управлять этими вещами. Например, если я хочу нарисовать сцену и отрисовать на ней квадраты с помощью цикла (к примеру, как в игре "Морской бой"). Мы же должна хорошо понимать и знать координаты сцены и самого объекта отрисовки. Особенно, координаты углов самого объекта.
Заранее благодарю за ответ, Евгений!

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
d
  • dsfs
  • 26 апреля 2024 г. 4:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80баллов,
  • Очки рейтинга4
d
  • dsfs
  • 26 апреля 2024 г. 4:45

C++ - Тест 002. Константы

  • Результат:50баллов,
  • Очки рейтинга-4
d
  • dsfs
  • 26 апреля 2024 г. 4:35

C++ - Тест 001. Первая программа и типы данных

  • Результат:73баллов,
  • Очки рейтинга1
Последние комментарии
k
kmssr8 февраля 2024 г. 18:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 1:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 10:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 8:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 декабря 2023 г. 21:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
G
Gar22 апреля 2024 г. 5:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 апреля 2024 г. 7:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 апреля 2024 г. 6:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 2:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 4:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Следите за нами в социальных сетях