Evgenii Legotckoi
14 сентября 2015 г. 22:36

Qt/C++ - Урок 018. QGraphicsItem - наследование и СЛОТы

А теперь поговорим немного о наследовании от QGraphicsItem и применении системы СИГНАЛ ов и СЛОТ ов при взаимодействии с графическими объектами на графической сцене QGraphicsScene. В задачу данного урока входит создание приложения, в котором на графической сцене будет отображаться объект класса QGraphicsItem , по нажатию на который будет появляться диалоговое окно QMessageBox , сигнализирующее о событии нажатия на графический объект.

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

Структура проекта для работы с QGraphicsItem

В структура данного проекта входят:

  • TestPoint.pro - профайл проекта;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp - файл исходных кодов основного окна приложения;
  • mypoint.h - заголовочный код класса, отнаследованного от QGraphicsItem;
  • mypoint.cpp - соответственно исходный код;
  • main.cpp - основной файл, с которого стартует приложение, в уроке не рассматривается, поскольку создаётся по умолчанию;
  • mainwindow.ui - файл дизайна главного окна.

mainwindow.ui

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

mainwindow.h

Файл примечателен лишь объявлением графической сцены, нашего нового класса MyPoint и СЛОТа для обработки СИГНАЛа из MyPoint.

  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3.  
  4. #include <QMainWindow>
  5. #include <QGraphicsScene>
  6. #include <QMessageBox>
  7.  
  8. #include <mypoint.h>
  9.  
  10. namespace Ui {
  11. class MainWindow;
  12. }
  13.  
  14. class MainWindow : public QMainWindow
  15. {
  16. Q_OBJECT
  17.  
  18. public:
  19. explicit MainWindow(QWidget *parent = 0);
  20. ~MainWindow();
  21.  
  22. private:
  23. Ui::MainWindow *ui;
  24. /* Объявляем графическую сцену и Точку с которой будем работать */
  25. QGraphicsScene *scene;
  26. MyPoint *point;
  27.  
  28. private slots:
  29. /* Слот для обработки сигнала из точки */
  30. void slotFromPoint();
  31. };
  32.  
  33. #endif // MAINWINDOW_H

mainwindow.cpp

Здесь уже поинтереснее. В данном файле выполняем реализацию СЛОТа, а также подключаем это СЛОТ к объекту класса MyPoint. А также добавляем данный объект на графическую сцену.

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3.  
  4. MainWindow::MainWindow(QWidget *parent) :
  5. QMainWindow(parent),
  6. ui(new Ui::MainWindow)
  7. {
  8. ui->setupUi(this);
  9.  
  10. /* Инициализируем графическую сцену с точку с которой будем работать */
  11. scene = new QGraphicsScene();
  12. point = new MyPoint();
  13.  
  14. /* Подключаем сигнал из точки к СЛОТу в главном классе */
  15. connect(point,SIGNAL(signal1()),this, SLOT(slotFromPoint()));
  16.  
  17. /* Устанавливаем графическую сцену в виджет */
  18. ui->graphicsView->setScene(scene);
  19. scene->addItem(point); // И добавляем на сцену точку
  20. }
  21.  
  22. MainWindow::~MainWindow()
  23. {
  24. delete ui;
  25. }
  26.  
  27. void MainWindow::slotFromPoint()
  28. {
  29. QMessageBox::information(this,
  30. "Зафиксировано нажатие",
  31. "Вы нажали на точку!!!"
  32. "\n"
  33. "\n"
  34. "\n С Уважением, Ваш КЭП!!!");
  35. }

mypoint.h

Ключевым моментом в данном файле является то, что в данном классе применено множественное наследование, а именно то, что Мы отнаследовались не только от QGraphicsItem, но и от QObject. Дело в том, что если не наследоваться от QObject, то СИНГАЛы и СЛОТы не будут работать и проект не скомпилируется, если вы будете применять функцию connect для подключения СИГНАЛа из MyPoint, к СЛОТу в MainWindow.

  1. #ifndef MYPOINT_H
  2. #define MYPOINT_H
  3.  
  4. #include <QObject>
  5. #include <QGraphicsItem>
  6. #include <QPainter>
  7.  
  8. /* Чтобы работали СЛОТЫ и СИГНАЛЫ, наследуемся от QOBJECT,
  9. * */
  10. class MyPoint : public QObject, public QGraphicsItem
  11. {
  12. Q_OBJECT
  13. public:
  14. explicit MyPoint(QObject *parent = 0);
  15. ~MyPoint();
  16.  
  17. signals:
  18. /* Сигнал, который будет посылаться в том случае,
  19. * если произошел клик мышью по объекту
  20. * */
  21. void signal1();
  22.  
  23. protected:
  24. /* Перегружаем метод нажатия мышью, для его перехвата
  25. * */
  26. void mousePressEvent(QGraphicsSceneMouseEvent *event);
  27.  
  28. private:
  29. /* Данные методы виртуальные, поэтому их необходимо реализовать
  30. * в случае наследования от QGraphicsItem
  31. * */
  32. QRectF boundingRect() const;
  33. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  34. };
  35.  
  36. #endif // MYPOINT_H

mypoint.cpp

Самое главное, на что рекомендую обратить внимание в данном классе, так это на то, что мы переопределяем метод для вызова события нажатия на графический объект правой кнопкой мыши. И вызываем в данном методе СИГНАЛ.

  1. #include "mypoint.h"
  2.  
  3. MyPoint::MyPoint(QObject *parent)
  4. : QObject(parent), QGraphicsItem()
  5. {
  6.  
  7. }
  8.  
  9. MyPoint::~MyPoint()
  10. {
  11.  
  12. }
  13.  
  14. QRectF MyPoint::boundingRect() const
  15. {
  16. /* возвращаем координаты расположения точки
  17. * по ним будет определяться нажатие точки
  18. * */
  19. return QRectF(0,0,100,100);
  20. }
  21.  
  22. void MyPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  23. {
  24. // Устанавливаем кисть в QPainter и отрисовываем круг, то есть ТОЧКУ
  25. painter->setBrush(Qt::black);
  26. painter->drawEllipse(QRectF(0, 0, 100, 100));
  27. Q_UNUSED(option);
  28. Q_UNUSED(widget);
  29. }
  30.  
  31. /* Переопределив метод перехвата события нажатия кнопки мыши,
  32. * добавляем посылку СИГНАЛА от объекта
  33. * */
  34. void MyPoint::mousePressEvent(QGraphicsSceneMouseEvent *event)
  35. {
  36. emit signal1();
  37. // Вызываем родительскую функцию события нажатия кнопки мыши
  38. QGraphicsItem::mousePressEvent(event);
  39. }

Итог

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

Видеоурок

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

E
  • 11 апреля 2019 г. 18:15

Здравствуйте. А где описание функции signal1()?

Evgenii Legotckoi
  • 11 апреля 2019 г. 18:29

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

E
  • 11 апреля 2019 г. 18:49

Спасибо за ответ) У меня компоновщик на нее ругался просто. Оказалось, просто забыл Q_OBJECT в начале класса указать.

Комментарии

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