Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Ilya_181 от Август 08, 2017, 11:02



Название: Динамическое создание обьектов
Отправлено: Ilya_181 от Август 08, 2017, 11:02
Вопрос 1: Благодаря системе объектных иерархий с разработчика снимается необходимость самому заботиться об освобождении памяти от созданных объектов.
     Конструктор класса QObject выглядит следующим образом:
    QObject (QObject* pobj = 0);

QObject* pobjl = new QObject;
QObject* pobj2 = new QObject (pobjl) ;
QObject* pobj4 = new QObject (pobj2) ;
QObject* pobj3 = new QObject (pobjl) ;

Однако я не могу понять кто удалит pobjl? Понятно что (pobj2, pobj3, pobj4) удаляться, поскольку у каждого из них есть предок.


Вопрос 2:
QObject (QObject* pobj = 0);
Правильно я понимаю? Такая запись в конструкторе означает, что при динамическом создании объекта, если мы ничего не передадим ему в конструктор, объект будет создан как (объект верхнего уровня).


Вопрос 3:
class My_ComboBox : public QComboBox
{
    Q_OBJECT
public:
    explicit My_ComboBox(QWidget *parent = 0)
    {
        setParent(parent);
     }
}

Нужно ли реализовывать метод setParent(parent);? Кажется что нужно, для того чтобы, когда мы динамически создадим объект этого класса, и в конструктор передадим предка, это метод установит указатель. Может я что-то не так понимаю сори...

Вопрос 4:
QGraphicsScene  scene;

QGraphicsTextltem* textltem = new  QGraphicsTextltem(?)
QGraphicsRectItem *rectItem = new QGraphicsRectItem(textltem)
QGraphicsRectItem *rectItem2 = new QGraphicsRectItem(rectItem2)

Дело в том что, в конструкторы QGraphics____ltem-ов можно передать предок QGraphicsItem, что и происходит с rectItem и rectItem2 . Но что передавать в textltem? Ему тоже нужно передать предка. Можно было бы предать сцену (scene), но textltem не принимает в качестве предка сцену. Кто же тогда удалит textltem?


Вопрос 5:
Простите и последний вопрос.

class My_QToolButton : public QAbstractButton
{
explicit My_QToolButton (QWidget *parent = Q_NULLPTR);

}

Если в конструкторе я поменяю вместо QWidget поставлю (explicit My_QToolButton (QToolButton *parent = Q_NULLPTR);)
Получается в качестве предка кнопка My_QToolButton должна будет получать себе подобный виджет? Это как-то повлияет на поведение виджета или программы? В смысле, небезопасны такие замены? Понятно что, в данном случае сужаются варианты предков, вопрос в том, можно так делать? И что значит Q_NULLPTR?


Название: Re: Динамическое создание обьектов
Отправлено: __Heaven__ от Август 08, 2017, 11:17
1. pobjl из-за отсутствия родителя никем не удалится автоматически.
2. Да.
3. Для передачи родителя достаточно вызвать конструктор базового класса
Код
C++ (Qt)
class My_ComboBox : public QComboBox
{
   Q_OBJECT
public:
   explicit My_ComboBox(QWidget *parent = 0)
       : QComboBox (parent)
   {
    }
}
Метод setParent уже реализован в QComboBox и не требует повторной реализации.
4. Если не ошибаюсь, сцен может быть несколько для отображения одного и того же объекта. Соответственно 2 сцены не могут владеть одним объектом. Высвобождать память здесь должен программист.
5. Зачем кнопке делать родителя кнопку? Вы делаете виджет кнопка в кнопке?


Название: Re: Динамическое создание обьектов
Отправлено: lit-uriy от Август 08, 2017, 14:53
Дополню:
1. Кроме программиста удалить его некому;
2. "как (объект верхнего уровня)", как ОКНО;
3. Нет, делай как написал __Heaven__, т.е. инициализируй конструктор базового класса : QComboBox (parent)
4. "Кто же тогда удалит textltem?"
Если элемент добавлен на сцену, с помощью
void QGraphicsScene::addItem(QGraphicsItem *item)
, то сцена становится владельцем элемента и при её удалении она удалит всё что она содержит
__Heaven__ не прав:
"If the item is already in a different scene, it will first be removed from its old scene, and then added to this scene as a top-level."

5. изменение сигнатуры своего собственного конструктора никак не влияет на дочерне-родительские связи. Дочерне родительские связи определяются либо методом setParent(), либо инициализацией базового класса.
Например:
Код
C++ (Qt)
class My_QToolButton : public QAbstractButton
{
explicit My_QToolButton (QToolButton *sibling = Q_NULLPTR)
: QAbstractButton(this) // Установили этот экземпляр в качестве родителя для базового
{
// что-то тут
}
}
 
в этом коде конструктор базового класса инициализирован указателем на Этот экземпляр,
но пока Этому экземпляру не задан родитель (теперь остаётся только одна возможность - setParent() ) Этот экзепляр надо будет удалять ручками.

Я умышленно обозвал аргумент конструктора иначе, чтобы его имя тебя не смущало - оно ничего не значит.


Название: Re: Динамическое создание обьектов
Отправлено: __Heaven__ от Август 08, 2017, 17:04
Юрий, кажется в 5 из-за передачи this конструктору базового класса мы породим рекурсию в деструкторе.


Название: Re: Динамическое создание обьектов
Отправлено: Ilya_181 от Август 08, 2017, 19:19
5. Зачем кнопке делать родителя кнопку? Вы делаете виджет кнопка в кнопке?

Что-то я не подумал. Я придумал на ходу, неудачно. Забыл что все дочерние виджеты находятся внутри виджета предка. Дальше именно как я хочу сделать с графическим представлением.

Вариант 1:   Создаю собственный класс. В конструкторе инициализирую конструктор базового класса. В MainWindow  создаю объекты передавая в них предка, и объект без предка удаляю сам.

Код
C++ (Qt)
#include <QGraphicsTextItem>
 
class my_QGraphicsTextItem : public QGraphicsTextItem
{
   Q_OBJECT
 
public:
   explicit my_QGraphicsTextItem(QGraphicsItem *parent = Q_NULLPTR) : QGraphicsTextItem (parent) {}
 
};
 
-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------
 
class MainWindow : public QMainWindow
{
   Q_OBJECT
 
public:
   explicit MainWindow(QWidget *parent = 0)
           {
 
           QGraphicsScene scene;
 
           my_QGraphicsTextItem *text = new my_QGraphicsTextItem;
           my_QGraphicsTextItem *text2= new my_QGraphicsTextItem(text);
           my_QGraphicsTextItem *text3 = new my_QGraphicsTextItem(text2);
 
           scene.addItem(text );
           scene.addItem(text2 );
           scene.addItem(text3 );
            }
          ~MainWindow()
           { delete text ; }
 
};


Вариант 2:   Создаю собственный класс. В конструкторе инициализирую конструктор базового класса. Но в отличии от предыдущего класса, этот в качестве предка принимает не QGraphicsItem а QGraphicsScene. В MainWindow  создаю объекты передавая в них предка, и так получается у всех есть предок сцена. И ничего удалять не приходится. Сцена создана не динамически.

Код
C++ (Qt)
#include <QGraphicsTextItem>
 
class my_QGraphicsTextItem : public QGraphicsTextItem
{
   Q_OBJECT
 
public:
   explicit my_QGraphicsTextItem(QGraphicsScene *parent = Q_NULLPTR) : QGraphicsTextItem (parent) {}
 
};
 
-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------
 
class MainWindow : public QMainWindow
{
   Q_OBJECT
 
public:
   explicit MainWindow(QWidget *parent = 0)
           {
 
           QGraphicsScene scene;
 
           my_QGraphicsTextItem *text  = new my_QGraphicsTextItem(&scene);
           my_QGraphicsTextItem *text2 = new my_QGraphicsTextItem(&scene);
           my_QGraphicsTextItem *text3 = new my_QGraphicsTextItem(&scene);
 
           scene.addItem(text );
           scene.addItem(text2 );
           scene.addItem(text3 );
            }
          ~MainWindow();
 
};


Вопрос 1: Какой из этих вариантов лучше сделать?
Вопрос 2: В первом варианте я правильно удалил объект? В программировании немного, еще не приходилось удалять объекты.


Название: Re: Динамическое создание обьектов
Отправлено: __Heaven__ от Август 09, 2017, 09:14
Получается, что второй.
Цитировать
[virtual] QGraphicsScene::~QGraphicsScene()
Removes and deletes all items from the scene object before destroying the scene object. The scene object is removed from the application's global scene list, and it is removed from all associated views.
Сцена при разрушении потянет за собой всё своё содержимое.


Название: Re: Динамическое создание обьектов
Отправлено: Ilya_181 от Август 09, 2017, 11:32

[virtual] QGraphicsScene::~QGraphicsScene()
Removes and deletes all items from the scene object before destroying the scene object. The scene object is removed from the application's global scene list, and it is removed from all associated views.
Сцена при разрушении потянет за собой всё своё содержимое.
Вопрос 1: Выходит не нужно устанавливать предка к элементам сцены, поскольку они уничтожаться перед уничтожением сценой?
Код
C++ (Qt)
class my_QGraphicsTextItem : public QGraphicsTextItem
{
   Q_OBJECT
 
public:
   explicit my_QGraphicsTextItem(QGraphicsScene *parent = Q_NULLPTR) // : QGraphicsTextItem (parent) {}
   {}
};
И тут обнаружил что нельзя вызвать конструктор базового класса во втором варианте. Поскольку мой класс в качестве предка принимает сцену, а базовый класс QGraphicsItem. Приходится реализовывать без вызова базового конструктора.

Вопрос 2: Стоит так делать? Или сделать первый вариант?


Название: Re: Динамическое создание обьектов
Отправлено: __Heaven__ от Август 09, 2017, 14:05
Я невнимательно почитал #4.
Код
C++ (Qt)
class my_QGraphicsTextItem : public QGraphicsTextItem
{
   Q_OBJECT
 
public:
   explicit my_QGraphicsTextItem(QGraphicsTextItem*parent = Q_NULLPTR)
        : QGraphicsTextItem (parent) {}
 
};


Название: Re: Динамическое создание обьектов
Отправлено: lit-uriy от Август 10, 2017, 06:15
__Heaven__, пожалуй ты прав, насчёт моего примера


Название: Re: Динамическое создание обьектов
Отправлено: lit-uriy от Август 10, 2017, 06:24
Ilya_181, важное НЕпонимание у тебя по поводу "Графического представления".
В нём элементам устанавливают родителя только для того, чтобы получить иерархию графических элементов, а не системы удаления объектов.

Т.е. если есть два элемента Item1 и Item2,
1. оба не имеют родителя, после добавления обоих на сцену, сцена станет их владельцем - она удалит их сама, когда сработает деструктор сцены. Теперь командуешь первому элементу "повернись на 90 град", он, и только он повернётся на 90 град. Второй элемент останется неизменным.
2. Элемент Item1 является родителем для Item2, чтобы добавить оба на сцену, достаточно добавить только родительский элемент на сцену, дочерний попадёт на сцену автоматически.  Теперь командуешь первому элементу "повернись на 90 град", он одновременно со своими детьми повернётся на 90 град.

Тоже самое касается операций выделения (выделил родителя выделятся и его дети), перемещения (перемещаешь родителя - дети в месте с ним перемещаются).

Важно:
QGraphicsltem - не является наследником QObject, поэтому в графических элементах отсутствует механизм "сборки мусора" (автоматического удаления объектов), кроме случая, когда элементы находятся на сцене, тут уже сцена удаляет всё своё содержимое.


Название: Re: Динамическое создание обьектов
Отправлено: __Heaven__ от Август 10, 2017, 09:26
Дополню, что помимо автоматического удаления объектов сценой имеется автоматическое удаление детей при удалении топлевел айтема.


Название: Re: Динамическое создание обьектов
Отправлено: Ilya_181 от Август 12, 2017, 11:49
Ilya_181, важное НЕпонимание у тебя по поводу "Графического представления".
В нём элементам устанавливают родителя только для того, чтобы получить иерархию графических элементов, а не системы удаления объектов.

Т.е. если есть два элемента Item1 и Item2,
1. оба не имеют родителя, после добавления обоих на сцену, сцена станет их владельцем - она удалит их сама, когда сработает деструктор сцены. Теперь командуешь первому элементу "повернись на 90 град", он, и только он повернётся на 90 град. Второй элемент останется неизменным.
2. Элемент Item1 является родителем для Item2, чтобы добавить оба на сцену, достаточно добавить только родительский элемент на сцену, дочерний попадёт на сцену автоматически.  Теперь командуешь первому элементу "повернись на 90 град", он одновременно со своими детьми повернётся на 90 град.

Тоже самое касается операций выделения (выделил родителя выделятся и его дети), перемещения (перемещаешь родителя - дети в месте с ним перемещаются).

Важно:
QGraphicsltem - не является наследником QObject, поэтому в графических элементах отсутствует механизм "сборки мусора" (автоматического удаления объектов), кроме случая, когда элементы находятся на сцене, тут уже сцена удаляет всё своё содержимое.
Спасибо. Я понял. Тему можно закрывать.