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.

#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);
}

Итог

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

Видеоурок

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

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

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

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

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

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

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
  • Последние комментарии
  • Evgenii Legotckoi
    16 апреля 2025 г. 17:08
    Благодарю за отзыв. И вам желаю всяческих успехов!
  • IscanderChe
    12 апреля 2025 г. 17:12
    Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
  • AK
    1 апреля 2025 г. 11:41
    Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
  • Evgenii Legotckoi
    9 марта 2025 г. 21:02
    К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
  • VP
    9 марта 2025 г. 16:14
    Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…