А теперь поговорим немного о наследовании от 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.
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
- #include <QMainWindow>
- #include <QGraphicsScene>
- #include <QMessageBox>
- #include <mypoint.h>
- namespace Ui {
- class MainWindow;
- }
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
- public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
- private:
- Ui::MainWindow *ui;
- /* Объявляем графическую сцену и Точку с которой будем работать */
- QGraphicsScene *scene;
- MyPoint *point;
- private slots:
- /* Слот для обработки сигнала из точки */
- void slotFromPoint();
- };
- #endif // MAINWINDOW_H
mainwindow.cpp
Здесь уже поинтереснее. В данном файле выполняем реализацию СЛОТа, а также подключаем это СЛОТ к объекту класса MyPoint. А также добавляем данный объект на графическую сцену.
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- /* Инициализируем графическую сцену с точку с которой будем работать */
- scene = new QGraphicsScene();
- point = new MyPoint();
- /* Подключаем сигнал из точки к СЛОТу в главном классе */
- connect(point,SIGNAL(signal1()),this, SLOT(slotFromPoint()));
- /* Устанавливаем графическую сцену в виджет */
- ui->graphicsView->setScene(scene);
- scene->addItem(point); // И добавляем на сцену точку
- }
- MainWindow::~MainWindow()
- {
- delete ui;
- }
- void MainWindow::slotFromPoint()
- {
- QMessageBox::information(this,
- "Зафиксировано нажатие",
- "Вы нажали на точку!!!"
- "\n"
- "\n"
- "\n С Уважением, Ваш КЭП!!!");
- }
mypoint.h
Ключевым моментом в данном файле является то, что в данном классе применено множественное наследование, а именно то, что Мы отнаследовались не только от QGraphicsItem, но и от QObject. Дело в том, что если не наследоваться от QObject, то СИНГАЛы и СЛОТы не будут работать и проект не скомпилируется, если вы будете применять функцию connect для подключения СИГНАЛа из MyPoint, к СЛОТу в MainWindow.
- #ifndef MYPOINT_H
- #define MYPOINT_H
- #include <QObject>
- #include <QGraphicsItem>
- #include <QPainter>
- /* Чтобы работали СЛОТЫ и СИГНАЛЫ, наследуемся от QOBJECT,
- * */
- class MyPoint : public QObject, public QGraphicsItem
- {
- Q_OBJECT
- public:
- explicit MyPoint(QObject *parent = 0);
- ~MyPoint();
- signals:
- /* Сигнал, который будет посылаться в том случае,
- * если произошел клик мышью по объекту
- * */
- void signal1();
- protected:
- /* Перегружаем метод нажатия мышью, для его перехвата
- * */
- void mousePressEvent(QGraphicsSceneMouseEvent *event);
- private:
- /* Данные методы виртуальные, поэтому их необходимо реализовать
- * в случае наследования от QGraphicsItem
- * */
- QRectF boundingRect() const;
- void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
- };
- #endif // MYPOINT_H
mypoint.cpp
Самое главное, на что рекомендую обратить внимание в данном классе, так это на то, что мы переопределяем метод для вызова события нажатия на графический объект правой кнопкой мыши. И вызываем в данном методе СИГНАЛ.
- #include "mypoint.h"
- MyPoint::MyPoint(QObject *parent)
- : QObject(parent), QGraphicsItem()
- {
- }
- MyPoint::~MyPoint()
- {
- }
- QRectF MyPoint::boundingRect() const
- {
- /* возвращаем координаты расположения точки
- * по ним будет определяться нажатие точки
- * */
- return QRectF(0,0,100,100);
- }
- void MyPoint::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
- {
- // Устанавливаем кисть в QPainter и отрисовываем круг, то есть ТОЧКУ
- painter->setBrush(Qt::black);
- painter->drawEllipse(QRectF(0, 0, 100, 100));
- Q_UNUSED(option);
- Q_UNUSED(widget);
- }
- /* Переопределив метод перехвата события нажатия кнопки мыши,
- * добавляем посылку СИГНАЛА от объекта
- * */
- void MyPoint::mousePressEvent(QGraphicsSceneMouseEvent *event)
- {
- emit signal1();
- // Вызываем родительскую функцию события нажатия кнопки мыши
- QGraphicsItem::mousePressEvent(event);
- }
Итог
В результате у Вас должно получиться следующее приложение, которое выводит в окне черный круг, при нажатии на который выскакивает диалоговое окно. Также вы можете ознакомиться с видеоуроком по этой статье, в котором показана демонстрация работы приложения и даны дополнительные пояснения к программному коду.
Здравствуйте. А где описание функции signal1()?
Добрый день. Вы имели ввиду реализацию? Для сигналов в Qt реализация не пишется, это всё генерируется в moc файлах под капотом Qt.
Спасибо за ответ) У меня компоновщик на нее ругался просто. Оказалось, просто забыл Q_OBJECT в начале класса указать.