А теперь поговорим немного о наследовании от 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 в начале класса указать.