Evgenii Legotckoi
17 сентября 2015 г. 20: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

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

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QGraphicsScene>
  6.  
  7. #include <triangle.h>
  8.  
  9. namespace Ui {
  10. class Widget;
  11. }
  12.  
  13. class Widget : public QWidget
  14. {
  15. Q_OBJECT
  16.  
  17. public:
  18. explicit Widget(QWidget *parent = 0);
  19. ~Widget();
  20.  
  21. private:
  22. Ui::Widget *ui;
  23. QGraphicsScene *scene; // Объявляем графическую сцену
  24. Triangle *triangle; // и треугольник
  25. };
  26.  
  27. #endif // WIDGET_H

widget.cpp

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

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3.  
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. this->resize(600,600); // Задаем размеры виджета, то есть окна
  10. this->setFixedSize(600,600); // Фиксируем размеры виджета
  11.  
  12. scene = new QGraphicsScene(); // Инициализируем графическую сцену
  13. triangle = new Triangle(); // Инициализируем треугольник
  14.  
  15. ui->graphicsView->setScene(scene); // Устанавливаем графическую сцену в graphicsView
  16. ui->graphicsView->setRenderHint(QPainter::Antialiasing); // Устанавливаем сглаживание
  17. ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по вертикали
  18. ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по горизонтали
  19.  
  20. scene->setSceneRect(-250,-250,500,500); // Устанавливаем область графической сцены
  21.  
  22. scene->addLine(-250,0,250,0,QPen(Qt::black)); // Добавляем горизонтальную линию через центр
  23. scene->addLine(0,-250,0,250,QPen(Qt::black)); // Добавляем вертикальную линию через центр
  24.  
  25. scene->addItem(triangle); // Добавляем на сцену треугольник
  26. triangle->setPos(0,0); // Устанавливаем треугольник в центр сцены
  27.  
  28.  
  29. }
  30.  
  31. Widget::~Widget()
  32. {
  33. delete ui;
  34. }

triangle.h

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

  1. #ifndef TRIANGLE_H
  2. #define TRIANGLE_H
  3.  
  4. #include <QGraphicsItem>
  5. #include <QPainter>
  6.  
  7. // Наследуемся от QGraphicsItem
  8. class Triangle : public QGraphicsItem
  9. {
  10. public:
  11. Triangle();
  12. ~Triangle();
  13.  
  14. protected:
  15. QRectF boundingRect() const; /* Определяем виртуальный метод,
  16. * который возвращает область, в которой
  17. * находится треугольник
  18. * */
  19. /* Определяем метод для отрисовки треугольника
  20. * */
  21. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  22. };
  23.  
  24. #endif // TRIANGLE_H

triangle.cpp

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

  1. #include "triangle.h"
  2.  
  3. Triangle::Triangle() :
  4. QGraphicsItem()
  5. {
  6.  
  7. }
  8.  
  9. Triangle::~Triangle()
  10. {
  11.  
  12. }
  13.  
  14. QRectF Triangle::boundingRect() const
  15. {
  16. return QRectF(-25,-40,50,80); // Ограничиваем область, в которой лежит треугольник
  17. }
  18.  
  19. void Triangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  20. {
  21. QPolygon polygon; // Используем класс полигона, чтобы отрисовать треугольник
  22. // Помещаем координаты точек в полигональную модель
  23. polygon << QPoint(0,-40) << QPoint(25,40) << QPoint(-25,40);
  24. painter->setBrush(Qt::red); // Устанавливаем кисть, которой будем отрисовывать объект
  25. painter->drawPolygon(polygon); // Рисуем треугольник по полигональной модели
  26. Q_UNUSED(option);
  27. Q_UNUSED(widget);
  28. }

Итог

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

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

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

Видеоурок

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь