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

QGraphicsItem, QGraphicsItem example, QGraphicsItem Qt, QGraphicsItem слот, Qt, множественное наследование

А теперь поговорим немного о наследовании от 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);
}

Итог

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

Видеоурок

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.
Поддержать автора Donate
E
  • #
  • 11 апреля 2019 г. 12:15

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

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

E

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

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
m
19 мая 2019 г. 1:49
mahhaki

Qt - Тест 001. Сигналы и слоты

  • Результат:78баллов,
  • Очки рейтинга2
S
17 мая 2019 г. 13:14
SunBro

Qt - Тест 001. Сигналы и слоты

  • Результат:42баллов,
  • Очки рейтинга-8
b
17 мая 2019 г. 4:18
banana

C++ - Тест 003. Условия и циклы

  • Результат:57баллов,
  • Очки рейтинга-2
Последние комментарии
21 мая 2019 г. 20:10
Дмитрий

Приветствую! Я думаю дойдёт и до этого, но пока изучать его у меня нет желания.
20 мая 2019 г. 19:20
Евгений Легоцкой

Добрый день! Вы не думали разместить репозиторий проекта на GitHub?
P.
18 мая 2019 г. 14:03
PELMYACH .

Спасибо большое! Вскоре буду разбираться!
18 мая 2019 г. 9:13
Евгений Легоцкой

Добрый день! Отнимать значение общего счётчика можно в деструкторе класса кнопки QDynamicButton::~QDynamicButton(){ ResID--;} При этом я бы ещё переустанавливал значения вс...
P.
14 мая 2019 г. 22:33
PELMYACH .

Здравствуйте!А не подскажите, как можно при удалении какой либо кнопки, у щётчика отнять значение?Дабы например четвёртой кнопке соответствовал ID 4, а не 5 скажем
Сейчас обсуждают на форуме
ДТ
22 мая 2019 г. 13:40
Даниил Тетерин

Есть задание - сделать программу-расписание, где главное окно - календарь, в котором можно нажать на любой день, тогда откроется окно, в котором будут видны уже существующие на этот день зад...
В
22 мая 2019 г. 10:05
Владислав

Данный код компилируется только для 32 битной системы, а на 64 битной выдаёт ошибку линковки LNK2019. Возможно ли как-то, используя функцию RegisterHotKey, использовать глобальные горячие клав...
I
22 мая 2019 г. 5:08
Intruder

Евгений, доброго времени суток и спасибо! Все получилось.
20 мая 2019 г. 8:43
Михаиллл

Кинул библиотеки в папку с проектом и в папку к компилируемым файлам.В файле проекта прописал так, но все равно выдает ту же ошибку QT += core gui networkgreaterThan(QT_MAJOR_VERSI...
20 мая 2019 г. 1:47
linq

Что вы понимаете под статической сборкой приложений? В какой среде?

Для зарегистрированных пользователей на сайте присутствует минимальное количество рекламы

EVILEG
О нас
Услуги
Присоединяйтесь к нам
© EVILEG 2015-2019
Рекомендует хостинг TIMEWEB