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