P
Peknic30 червня 2016 р. 04:17

Присвоение ID объекту и обращение к нему

id, item, qlist, Qt

Имеются объекты на сцене. Необходимо определять расстояние между объектами. Решил объекты пронумеровать.А как сказать qt что мне нужна координата n-го объекта, а потом другого объекта.
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

11
Evgenii Legotckoi
  • 30 червня 2016 р. 05:22

Рассмотрим такой пример. Имеются прямоугольники, при создании которых происходит инкрементирование счётчика ID и каждый раз на сцену добавляется объект с уникальным ID. Для этого нужно будет создать отдельный класс, который реализует данную логику. Далее, добавим на графическую сцену 20 таких объектов и проведём между двумя из них прямую линию. Допустим между 5-ым и 10-ым. То есть ID у них будут равны 5 и 10, соответственно.

Заголовочный файл прямоугольника

#ifndef RECTANGLE_H
#define RECTANGLE_H
 
#include <QObject>
#include <QGraphicsItem>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
 
class Rectangle : public QGraphicsItem
{
 
public:
    explicit Rectangle();
    static int countId;         // Статическая переменная, счетчик номеров прямоугольников
    int getId() const;          // Функция для возврата локального номера прямоугольника
 
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
    QRectF boundingRect() const override;
 
private:
    int m_id;   // ID прямоугольника
};
 
#endif // RECTANGLE_H

Исходный код прямоугольника

#include "rectangle.h"
 
Rectangle::Rectangle() : QGraphicsItem()
{
    countId++;
    m_id = countId;
}
 
int Rectangle::getId() const
{
    return m_id;
}
 
void Rectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setPen(Qt::black);
    painter->setBrush(Qt::green);
    painter->drawRect(-10, -10, 20, 20);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}
 
QRectF Rectangle::boundingRect() const
{
    return QRectF (-10, -10, 20, 20);
}
 
int Rectangle::countId = 0;  // Тот самый статический счётчик

Проработаем всё это дело в главном окне приложения, в которому у нас будет создана графическая сцена.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <QGraphicsScene>
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    Ui::MainWindow *ui;
    QGraphicsScene *scene;
};
 
#endif // MAINWINDOW_H

Ну и проработаем всю логику, которая была написана в начале

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include "rectangle.h"
 
/* Функция для получения рандомного числа
 * в диапазоне от минимального до максимального
 * */
static int randomBetween(int low, int high)
{
    return (qrand() % ((high + 1) - low) + low);
}
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->resize(600, 600);                 // Изменим размер главного окна приложения
    scene = new QGraphicsScene(this);       // Инициализируем графическую сцену
    ui->graphicsView->setScene(scene);      // Установим сцену в Graphics View
    scene->setSceneRect(0, 0, 500, 500);    // Установим размеры сцены
 
    // Создадим 20 прямоугольников со случайными координатами
    for (auto i = 0; i < 20; i++) {
        Rectangle *rect = new Rectangle();
        rect->setX(randomBetween(15, 485));
        rect->setY(randomBetween(15, 485));
        scene->addItem(rect);
    }
 
    // Временные указатели на прямоугольники, координаты которых нас будут интересовать
    Rectangle *item_1;
    Rectangle *item_2;
 
    // Пройдёмся по всем объектам на грфической сцене, чтобы найти нужные
    foreach (QGraphicsItem *item, scene->items()) {
        // Необходимо скастовать QGraphicsItem в объект класса прямоугольника,
        // чтобы получить доступ к его ID
        Rectangle *rect = static_cast<Rectangle *>(item);
        // Если ID равен 5 или 10, то сохраним указатель на него в соответсвующие указатели item_1 или item_2
        switch (rect->getId()) {
        case 5:
            item_1 = rect;
            break;
        case 10:
            item_2 = rect;
            break;
        default:
            break;
        }
    }
 
    if (item_1 != nullptr && item_2 != nullptr) {
        // создадим линию между этими двумя объектами
        QLineF lineBetweenItems;
        lineBetweenItems.setP1(item_1->scenePos()); // используем координаты прямоугольников на сцене,
        lineBetweenItems.setP2(item_2->scenePos()); // чтобы задать положение концов линии
 
        // добавляем линию на сцену
        scene->addLine(lineBetweenItems);
        qDebug() << lineBetweenItems.length(); // Выводим расстояние между объектами
    }
}
 
MainWindow::~MainWindow()
{
    delete ui;
}

    P
    • 06 липня 2016 р. 05:12

    Спасибо. Все работает. У меня еще вопросик. А как сделать так чтоб объект одного класса взаимодействовал только с определенным объектом другого класса ( связать объекты между собой, как на картинке) классы унаследованны от одного родителя. И как можно присвоить и отобразить имена объектов? Пробовал через Qlabel,не получилось.

      Evgenii Legotckoi
      • 06 липня 2016 р. 10:31
      • Відповідь була позначена як рішення.

      связать объекты между собой, как на картинке

      Ну если я правильно понял, то проблем в этом никаких быть не должно. В том примере, который я привел, будем считать, что класс Rectangle – это у нас базовый класс, от которого будут наследованы остальные классы. Таким образом у нас остаётся глобальная система id и для этого базового класса и для всех его наследников. Поэтому можно сделать допустим два класса наследника, и переопределить только вид их отрисовки. Например, у нас это будут красные и синие прямоугольники.
      Синий прямоугольник

      #ifndef RECTANGLEBLUE_H
      #define RECTANGLEBLUE_H
       
      #include "rectangle.h"
       
      class RectangleBlue : public Rectangle
      {
      public:
          RectangleBlue();
       
      protected:
          void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
          QRectF boundingRect() const override;
      };
       
      #endif // RECTANGLEBLUE_H
      #include "rectangleblue.h"
       
      RectangleBlue::RectangleBlue() : Rectangle()
      {
       
      }
       
      void RectangleBlue::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          painter->setPen(Qt::black);
          painter->setBrush(Qt::blue);
          painter->drawRect(-10, -10, 20, 20);
          painter->drawText(-10, 20, QString::number(getId()));
          Q_UNUSED(option);
          Q_UNUSED(widget);
      }
       
      QRectF RectangleBlue::boundingRect() const
      {
          return QRectF (-10, -10, 20, 30);
      }

      Красный прямоугольник

      #ifndef RECTANGLERED_H
      #define RECTANGLERED_H
       
      #include "rectangle.h"
       
      class RectangleRed : public Rectangle
      {
      public:
          RectangleRed();
       
      protected:
          void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
          QRectF boundingRect() const override;
      };
       
      #endif // RECTANGLERED_H
      #include "rectanglered.h"
       
      RectangleRed::RectangleRed() : Rectangle()
      {
       
      }
       
      void RectangleRed::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
      {
          painter->setPen(Qt::black);
          painter->setBrush(Qt::red);
          painter->drawRect(-10, -10, 20, 20);
          painter->drawText(-10, 20, QString::number(getId()));
          Q_UNUSED(option);
          Q_UNUSED(widget);
      }
       
      QRectF RectangleRed::boundingRect() const
      {
          return QRectF (-10, -10, 20, 30);
      }

      Ну а далее я приведу немного модифицированный код MainWindow, где вместо зеленных прямоугольников класса Rectangle, будут создавать его наследники, классов RectangleBlue и RectangleRed.
      Обращаю внимание на то, что во время перебора всех элементов, благодаря полиморфизму, их можно кастовать к их общему базовому классу Rectangle, у которого, также как и его наследников доступен метод getId().

      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      #include <QDebug>
      #include "rectangle.h"
      #include "rectanglered.h"
      #include "rectangleblue.h"
       
      /* Функция для получения рандомного числа
       * в диапазоне от минимального до максимального
       * */
      static int randomBetween(int low, int high)
      {
          return (qrand() % ((high + 1) - low) + low);
      }
       
      MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
          this->resize(600, 600);                 // Изменим размер главного окна приложения
          scene = new QGraphicsScene(this);       // Инициализируем графическую сцену
          ui->graphicsView->setScene(scene);      // Установим сцену в Graphics View
          scene->setSceneRect(0, 0, 500, 500);    // Установим размеры сцены
       
          // Создадим 10 красных прямоугольников со случайными координатами
          for (auto i = 0; i < 10; i++) {
              RectangleRed *rect = new RectangleRed();
              rect->setX(randomBetween(15, 485));
              rect->setY(randomBetween(15, 485));
              scene->addItem(rect);
          }
       
          // Создадим 20 синих прямоугольников со случайными координатами
          for (auto i = 0; i < 20; i++) {
              RectangleBlue *rect = new RectangleBlue();
              rect->setX(randomBetween(15, 485));
              rect->setY(randomBetween(15, 485));
              scene->addItem(rect);
          }
       
          // Временные указатели на прямоугольники, координаты которых нас будут интересовать
          Rectangle *item_1;
          Rectangle *item_2;
       
          // Пройдёмся по всем объектам на грфической сцене, чтобы найти нужные
          foreach (QGraphicsItem *item, scene->items()) {
              // Необходимо скастовать QGraphicsItem в объект класса прямоугольника,
              // чтобы получить доступ к его ID
              Rectangle *rect = static_cast<Rectangle *>(item);
              // Если ID равен 5 или 10, то сохраним указатель на него в соответсвующие указатели item_1 или item_2
              switch (rect->getId()) {
              case 5:
                  item_1 = rect;
                  break;
              case 15:
                  item_2 = rect;
                  break;
              default:
                  break;
              }
          }
       
          if (item_1 != nullptr && item_2 != nullptr) {
              // создадим линию между этими двумя объектами
              QLineF lineBetweenItems;
              lineBetweenItems.setP1(item_1->scenePos()); // используем координаты прямоугольников на сцене,
              lineBetweenItems.setP2(item_2->scenePos()); // чтобы задать положение концов линии
       
              // добавляем линию на сцену
              scene->addLine(lineBetweenItems);
              qDebug() << lineBetweenItems.length(); // Выводим расстояние между объектами
          }
      }
       
      MainWindow::~MainWindow()
      {
          delete ui;
      }

      Ну и там же в исходных кодах наследованных классов я добавил подпись под прямоугольниками.

        P
        • 08 липня 2016 р. 08:44

        Немного не верно объяснил. Сделать так, чтоб синие только с синими были связаны, а красные, например, как с красными, так и , допустим, с черными.

        Еще возникла такая проблема. При включении слота двойного клика мыши, перестаем отображаться на сцене planeAEW, унаследованный от plane,причем другие объекты классов, унаследованные от plane отображаются.

        plane.h

        planeaew.h

          P
          • 08 липня 2016 р. 08:47
          #include "plane.h"
          #include "mainwindow.h"
           
          int q=0;
           
          Plane::Plane(QObject *parent) : QObject(parent), QGraphicsItem()
          {
              ResID++;
              IDplane = ResID;
              n = ResID;
          }
           
          Plane::~Plane()
          {
           
          }
           
          QRectF Plane::boundingRect() const
          {
              return QRectF(-30,-20,30,40);   //ограничиваем область в которой лежит треугольник
          }
           
          void Plane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *MainWindow)
          {
              //рисуем самолет
              painter->setPen(QPen(Qt::black,2));
              painter->drawLine(0,0,-20,0);    //тело
              painter->drawLine(0,0,-4,3);     //нос
              painter->drawLine(0,0,-4,-3);    //нос
              painter->drawLine(-8,10,-8,-10); //крыло
              painter->drawLine(-11,10,-11,-10);//крыло
           
              //рисуем хвост
              QPolygon polygon;
              polygon << QPoint(-20,0) << QPoint(-24,3) << QPoint(-24,-3);
              painter->setBrush(Qt::black);
              painter->drawPolygon(polygon);
           
              //установим имя
              painter->drawText(-12, 20, QString::number(getID()));
           
              Q_UNUSED(option);
              Q_UNUSED(MainWindow);
           
          }
           
          //движение объекта
          void Plane::slotGameTimer()
          {
              if(q<=20)
              {
              setPos(mapToParent(2,-1));
              }
              else
              {
              setPos(mapToParent(2,0));
              }
              q++;
           
          //проверка выхода за границы поля
          //если объект выходит за заданные границы, то возвращаем его назад
              if(this->x() + 2 < 0)
              {
                  this->setX(0);//слева
              }
              if(this->x() - 2 > 600)
              {
                  emit signalStopTimer();
                  //this->deleteLater();
              }
              if(this->y() + 2 < -600)
              {
                  this->setY(-600);//сверху
              }
              if(this->y() - 2 > 0)
              {
                  this->setY(0);  //снизу
              }
              emit signalNumber();
          }
           
          void Plane::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
          {
              //устанавливаем объект в новую позицию
              this->setPos(mapToScene(event->pos()));
          }
           
          void Plane::mousePressEvent(QGraphicsSceneMouseEvent *event)
          {
              //при нажатии на элемент меняем курсор
              this->setCursor(QCursor(Qt::ClosedHandCursor));
              //emit signalNumber();
              Q_UNUSED(event);
          }
           
          void Plane::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
          {
              //после отпускания меняем курсор на стрелку
              this->setCursor(QCursor(Qt::ArrowCursor));
              Q_UNUSED(event);
          }
           
          //void Plane::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
          //{
          //    this->N = this->IDplane;
          //    Q_UNUSED(event);
          //}
           
          int Plane::getID() const
          {
              return IDplane;
          }
           
          int Plane::ResID = 0;
          int Plane::n=0;
          //int Plane::N;

           

            Evgenii Legotckoi
            • 08 липня 2016 р. 11:56

            Немного не верно объяснил. Сделать так, чтоб синие только с синими были связаны, а красные, например, как с красными, так и , допустим, с черными.

            Я Вам показал всю механику определения по ID способа “связывания” объектов. Всё остальное делается по аналогии. Для определения, к какому типу (то бишь классу) относится тот или иной объект перечитайте урок связанный с полиморфизмом
            Там имеется enum с перечислениями типов объектов. Такое перечисление можно сделать в базовом классе. А во всех наследованных от него объектах можно переопределить виртуальный метод type(), который относится к классу QGraphicsItem, от которого должен быть наследован уже ваш базовый класс, от которого наследуются все остальные графические объекты.

            То есть в заголовочном файле базового класса

            enum Types {
                RedBlock = UserType + 1,
                BlueBlock,
                GreenBlock,
                BlackBlock
            }

            В заголовочном файле классов наследников
            int type() const override

            и в файле исходных кодов классов наследников (Допустим в синем прямоугольнике)

            int type()
            {
             return BlueBlock;
            }

            И уже от возвращаемых типов можете плясать и связывать все объекты так, как вам будет угодно.

              Evgenii Legotckoi
              • 08 липня 2016 р. 12:10

              При включении слота двойного клика мыши, перестаем отображаться на сцене planeAEW

              А вот тут я понятия не имею, на первый взгляд, весь код в полном порядке. Ну в том плане, что не заметно чего-то криминального из-за чего бы объект должен был быть нерабочим.

                f
                • 01 травня 2018 р. 07:27

                А как нарисовать дугу, между объектами?

                painter.drawArc
                видимо не подходит, тк QPainter, не связан с  QGraphicsObject / QGraphicsItem.
                https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/DFAexample.svg/250px-DFAexample.svg.png
                хотелось бы уметь рисовать что нибудь похожее на это
                  f
                  • 01 травня 2018 р. 07:46
                  QGraphicsEllipseItem *arc = scene->addEllipse(QRectF(_source->scenePos(),
                              QSize(_source->scenePos().rx() - _destination->scenePos().rx(),
                                    _source->scenePos().ry() - _destination->scenePos().ry()) ));
                          arc->setSpanAngle(90 * 16);

                  Нашел setSpanAngle, но он вместо дуги рисует "кусок пирога"
                    f
                    • 01 травня 2018 р. 10:01
                    • (відредаговано)

                    И сразу вопрос как нарисовать стрелку с помощью линий?


                    void Widget::printArrow(QLineF lineF)
                    {
                        QGraphicsLineItem *line = new GraphicsLineItem();
                        QLineF ll1; // /\ острая часть стрелы
                        QLineF ll2; // /\ острая часть стрелы
                    
                        qreal x, y, angl, len = 20;
                        x = lineF.p2().x();
                        y = lineF.p2().y();
                        angl = lineF.angle();
                    
                        ll1.setLine(x, y,
                                    x + len * cos((angl - 30) * 3.14159265 / 180),
                                    y + len * cos((angl - 30) * 3.14159265 / 180));
                        ll2.setLine(x, y,
                                    x + len * cos((angl + 30) * 3.14159265 / 180),
                                    y + len * cos((angl + 30) * 3.14159265 / 180));
                    
                        QGraphicsLineItem *l1 = new QGraphicsLineItem(ll1);
                        QGraphicsLineItem *l2 = new QGraphicsLineItem(ll2);
                        line->setLine(lineF);
                        scene->addItem(line);
                        scene->addItem(l1);
                        scene->addItem(l2);
                    }

                    Почему то не работает. У двух линий козырька почему то всегда угол 315 или 135 градусов
                      f
                      • 01 травня 2018 р. 10:16

                      косяк со стрелкой у себя нашел. Надо было синус у игрека ставить а не косинус.

                      void Widget::printArrow(QLineF lineF)
                      {
                          GraphicsLineItem *line = new GraphicsLineItem();
                          QLineF ll1; // /\ острая часть стрелы
                          QLineF ll2; // /\ острая часть стрелы
                      
                          qreal x, y, angl, len = 20;
                          x = lineF.p2().x();
                          y = lineF.p2().y();
                          angl = lineF.angle();
                          ll1.setLine(x, y,
                                      x - len * cos((angl - 10) * 3.14159265 / 180),
                                      y + len * sin((angl - 10) * 3.14159265 / 180));
                          ll2.setLine(x, y,
                                      x - len * cos((angl + 10) * 3.14159265 / 180),
                                      y + len * sin((angl + 10) * 3.14159265 / 180));
                          QGraphicsLineItem *l1 = new QGraphicsLineItem(ll1);
                          QGraphicsLineItem *l2 = new QGraphicsLineItem(ll2);
                          line->setLine(lineF);
                          scene->addItem(line);
                          scene->addItem(l1);
                          scene->addItem(l2);
                      }

                        Коментарі

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

                        C++ - Тест 004. Указатели, Массивы и Циклы

                        • Результат:50бали,
                        • Рейтинг балів-4
                        m
                        • molni99
                        • 26 жовтня 2024 р. 11:37

                        C++ - Тест 004. Указатели, Массивы и Циклы

                        • Результат:80бали,
                        • Рейтинг балів4
                        m
                        • molni99
                        • 26 жовтня 2024 р. 11:29

                        C++ - Тест 004. Указатели, Массивы и Циклы

                        • Результат:20бали,
                        • Рейтинг балів-10
                        Останні коментарі
                        ИМ
                        Игорь Максимов22 листопада 2024 р. 22:51
                        Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                        Evgenii Legotckoi
                        Evgenii Legotckoi01 листопада 2024 р. 00:37
                        Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
                        A
                        ALO1ZE19 жовтня 2024 р. 18:19
                        Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                        ИМ
                        Игорь Максимов05 жовтня 2024 р. 17:51
                        Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                        d
                        dblas505 липня 2024 р. 21:02
                        QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                        Тепер обговоріть на форумі
                        Evgenii Legotckoi
                        Evgenii Legotckoi25 червня 2024 р. 01:11
                        добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                        t
                        tonypeachey115 листопада 2024 р. 17:04
                        google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
                        NSProject
                        NSProject04 червня 2022 р. 13:49
                        Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
                        9
                        9Anonim25 жовтня 2024 р. 19:10
                        Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

                        Слідкуйте за нами в соціальних мережах