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 в начале класса указать.

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up