Какое место подходит для инициализации QWidgets?


Как лучше всего инициализировать QWidgets, когда вы добавляете их программно?

Я могу придумать, как это сделать:

1) Создайте экземпляры в файле определения, а затем инициализируйте их в списке инициализаторов. Это кажется правильным способом, но он становится немного небрежным, чем больше QWidgets вам нужно добавить в окно.

class SomeWindow : QDialog{
...
private:
  QLabel label1;
  QLabel label2;
...
}

SomeWindow::SomeWindow(...) : QDialog(...),
 label('label1 text'), label('label2 text')
{
...
  layout.addWidget(&label1);
  layout.addWidget(&label2);
...
}

2) исходя из C#, мне это нравится, но, похоже, это порождает утечку памяти...

SomeWindow::SomeWindow(...) : QDialog(...)
{
  QLabel* label1 = new QLabel('label1 text');
  QLabel* label2 = new QLabel('label2 text');
...
  layout.addWidget(label1);
  layout.addWidget(label2);
...
}

Есть ли лучший способ сделать это это то, чего мне не хватает?

Я извиняюсь за вопрос новичка.

3 4

3 ответа:

Qt использует свою собственную систему для удаления родительско-дочерних производных классов QObject. При удалении объекта все дочерние элементы также удаляются.

С первым кодом у вас есть 2 деструкции (в деструкторе SomeWindow и с системой QObject), то этот код является незаконным (только с Qt ; со стандартным кодом C++, это хорошо)

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

@Jairo

Настройка родитель в конструкторе-это не единственный способ добавления потомков к объектам. В частности, здесь, QLayout:: addWidget reparent objects (если макет правильно дочерний объект)

@msgmaxim

Будьте осторожны, макет не должен быть локальной переменной в конструкторе

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

Кроме того, если у вас есть диалоговое окно и вы просто добавляете много виджетов, таких как QLabel, вы можете сделать код аккуратнее, выполнив это в реализации: -

layout.addWidget(new QLabel('label1 text'));
layout.addWidget(new QLabel('label2 text'));
layout.addWidget(new QLabel('label3 text'));
layout.addWidget(new QLabel('label4 text'));

Как уже упоминалось, Родительская система Qt позаботится об очистке виджетов, когда их родитель будет удален.

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

Два способа хороши для инициализации нового виджета.

В первом случае у вас есть метки в качестве объектов. Поэтому, когда какое-то окно будет уничтожено, они тоже будут уничтожены автоматически. Помните, что если у вас есть указатель на виджеты вместо объектов, вам нужно (и можно) удалить метки в деструктор диалога.

SomeWindow::~SomeWindow()
{
    delete label1;
    label2.deleteLater(); // A safer way to delete a widget. Thread-safe.
}

И во втором случае произойдет утечка памяти, потому что у вас нет способа удалить виджет в деструктор. Но если вы определяете родителя для меток, они будут удалить, когда родитель тоже удалить. Загляните вQWidget documentation .

Если родительский элемент равен 0, новый виджет становится окном. Если родителем является другой виджет, этот виджет становится дочерним окном внутри родителя. Новый виджет удаляется при удалении его родительского элемента.

Более того, всякий раз, когда конструктор объекта запрашивает у вас родительский QWidget или QObject, вы можете подумать, что Qt удалит объект, когда родитель будет удален.

Я тоже Ньюби, но надеюсь это поможет вам.