Получение родительского макета в Qt

быстрый вопрос. Есть ли способ (легко) получить родительский макет виджета в Qt?

PS: QObject :: parent () не будет работать по логическим причинам.

РЕДАКТИРОВАТЬ: Я уверен, что у виджета есть родительский макет, потому что я добавил его в макет ранее в коде. Теперь у меня есть много других макетов в окне, и хотя я могу их отслеживать, я просто хочу знать, есть ли простой и понятный способ получить родительский макет.

РЕДАКТИРОВАТЬ2: Извините, "легкий и чистый", вероятно, не лучший способ выразить это. Я имел в виду использование Qt API.

EDIT3: я добавляю виджет в макет следующим образом:

QHBoxLayout * layout = new QHBoxLayout;

макет-> addWidget (кнопка);


person Austin    schedule 09.03.2010    source источник
comment
Возвращает родительское окно.   -  person Austin    schedule 09.03.2010
comment
@Ronny, потому что QLayouts - это просто менеджеры. Управляемые объекты в макетах по-прежнему являются дочерними по отношению к их соответствующему родительскому элементу (например, Window). Это сделано для того, чтобы виджеты не зависели от макета (если таковой имеется), в котором они управляются.   -  person BastiBen    schedule 09.03.2010
comment
О, я вижу. Теперь у меня есть вопрос.   -  person Ronny Brendel    schedule 09.03.2010
comment
Блин, ребята. Что за странные голоса против сегодня? Кажется, что чем больше людей становится в SO, тем больше людей хотят заниматься серьезным модераторским делом. : /   -  person BastiBen    schedule 09.03.2010
comment
Можете ли вы показать, как вы создаете виджеты и настраиваете свои макеты? Или, по крайней мере, объясните, что вы имели в виду, говоря, что я добавил его в макет ранее в коде.   -  person Paul    schedule 09.03.2010
comment
Какая здесь настоящая цель? Доступ к макету, в котором находится виджет, без прохождения через родительский элемент, кажется плохой идеей.   -  person Adam W    schedule 09.03.2010


Ответы (7)


(Обновленный ответ)

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

Просто помните, что родительский элемент QWidget не изменяется, если он выровнен в макете.

Тогда вам, возможно, придется самому следить за этим.

person BastiBen    schedule 09.03.2010
comment
Это возвращает макет, содержащийся внутри вашего виджета (если есть), а не макет, содержащий ваш виджет. - person Austin; 09.03.2010
comment
Это возвращает макет, установленный в виджете, а не родительский макет виджета (то есть макет, в котором находится этот виджет). - person Lucas; 09.03.2010
comment
Но parent (). Layout () должен делать то, что они хотят. - person McBeth; 09.03.2010
comment
@McBeth, это не так. Виджет по-прежнему является дочерним элементом окна, а не макета. - person BastiBen; 09.03.2010
comment
@BastiBense Конечно, виджет является потомком своего родительского виджета. Но у этого родительского виджета есть макет (как утверждается OP), который может иметь дополнительные макеты, но исходный виджет будет где-то там. - person McBeth; 09.03.2010
comment
@BastiBense, на самом деле, вы можете узнать, есть ли у вас правильный макет, вызвав indexOf (widget *) в макете. Это немного утомительно, но это сработает. Я уже не уверен, что «легко» или «чисто» - это главное слово. Все будет достаточно общим, чтобы вы могли написать это один раз как отдельную функцию, но она будет работать. - person McBeth; 09.03.2010
comment
@McBeth, технически ты прав. Но поскольку вы не можете быть на 100% уверены в структуре макета, я предлагаю использовать более простой и безопасный подход вместо полного перебора всего. - person BastiBen; 12.03.2010

РЕШЕНО! Использование: QLayout * parentLayout = findParentLayout (addedWidget)

QLayout* findParentLayout(QWidget* w, QLayout* topLevelLayout)
{
  for (QObject* qo: topLevelLayout->children())
  {
     QLayout* layout = qobject_cast<QLayout*>(qo);
     if (layout != nullptr)
     {
        if (layout->indexOf(w) > -1)
          return layout;
        else if (!layout->children().isEmpty())
        {
          layout = findParentLayout(w, layout);
          if (layout != nullptr)
            return layout;
        }
     }
  }
  return nullptr;
}

QLayout* findParentLayout(QWidget* w)
{
    if (w->parentWidget() != nullptr)
        if (w->parentWidget()->layout() != nullptr)
            return findParentLayout(w, w->parentWidget()->layout());
    return nullptr;
}
person Ivan Babulic    schedule 12.05.2016

Просто используйте:

QHBoxLayout* parentLayout = button->parentWidget()->layout();

Я предполагаю, что button является дочерним элементом виджета, который содержит layout, который содержит button. button->parentWidget() возвращает указатель на виджет родительского элемента кнопки, а ->layout() возвращает указатель на макет родительского элемента.

person Otto V.    schedule 12.05.2016
comment
Обратите внимание, что в общем случае это не работает. Это предостережение подразумевается в этом ответе (я предполагаю, что кнопка является дочерним элементом виджета, который содержит макет, содержащий кнопку.), но @BastiBen явно говорит об этом в своем ответе: виджет технически может содержаться в нескольких макетах (например, горизонтальный макет, который выровнен внутри вертикального макета). Имейте это в виду, если вы планируете использовать это решение. - person waldyrious; 16.12.2016

используйте widget.parent (). layout () и перебор с поиском (включая рекурсию) - мой единственный совет. Может быть, вы можете выполнить поиск по "имени".

person Ronny Brendel    schedule 09.03.2010
comment
Я уже пробовал QObject :: parent (), и он не работает. Он возвращает родительское окно. - person Austin; 09.03.2010
comment
это означает, что родительский макет отсутствует. - person Ronny Brendel; 09.03.2010
comment
Если это виджет, вы можете использовать widget.layout (), если это то, что вы хотите - person Ronny Brendel; 09.03.2010
comment
Мне кажется, что вам нужно искать с помощью грубой силы, начиная с этого макета родительских виджетов. Я буду копать дальше. - person Ronny Brendel; 09.03.2010

После некоторого исследования я нашел «частичное» решение проблемы.

Если вы создаете макет и управляете с его помощью виджетом, вы можете получить этот макет позже в коде, используя динамические свойства Qt. Теперь, чтобы использовать QWidget :: setProperty (), объект, который вы собираетесь сохранить, должен быть зарегистрированным метатипом. Указатель на QHBoxLayout не является зарегистрированным метатипом, но есть два обходных пути. Самый простой обходной путь - зарегистрировать объект, добавив его в любом месте кода:

Q_DECLARE_METATYPE(QHBoxLayout*)

Второй способ - обернуть объект:

struct Layout {
    QHBoxLayout* layout;
};
Q_DECLARE_METATYPE(Layout)

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

QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
widget->setProperty("managingLayout", QVariant::fromValue(layout));
layout->addWidget(widget);

Или так, если вы использовали второй обходной путь:

QHBoxLayout* layout = new QHBoxLayout;
QWidget* widget = new QWidget;
Layout l;
l.layout = layout;
widget->setProperty("managingLayout", QVariant::fromValue(l));
layout->addWidget(widget);

Позже, когда вам понадобится получить макет, вы можете получить его следующим образом:

QHBoxLayout* layout = widget->property("managingLayout").value<QHBoxLayout*>();

Или вот так:

Layout l = widget->property("managingLayout").value<Layout>();
QHBoxLayout* layout = l.layout;

Этот подход применим только тогда, когда вы создали макет. Если вы не создали макет и не установили его, то получить его позже будет непросто. Также вам нужно будет отслеживать макет и при необходимости обновлять свойство manageLayout.

person Austin    schedule 13.03.2010

Вы пробовали это? Не забудьте проверить NULL.

QLayout *parent_layout = qobject_cast< QLayout* >( parent() );

Если parent_layout равно NULL, то родительский виджет не является макетом.

person Lucas    schedule 09.03.2010
comment
Я уверен, что у виджета есть родительский макет. - person Austin; 09.03.2010
comment
См. документ: макет будет автоматически переродить виджеты (используя QWidget :: setParent ()), чтобы они были потомками виджета, на котором установлен макет. - person Marek R; 03.02.2014

Вы пробовали QWidget::layout()?

person Paul    schedule 09.03.2010
comment
Кто-то уже предлагал это, но отредактировал. Этот не будет работать - причина в том, что он возвращает макет, установленный в виджете, а не макет, содержащий ваш виджет. - person Austin; 09.03.2010
comment
Что тогда вы имеете в виду под родительским макетом? Когда вы помещаете виджет в макет в Designer, вы фактически устанавливаете этот макет на виджет, этот макет не становится QObject::parent() этого виджета. В этом легко убедиться, если посмотреть на файл .h, созданный uic из файла .ui. - person Paul; 09.03.2010
comment
Я имел в виду, что после размещения моего виджета в макете A возможно ли с помощью Qt API получить макет A позже в коде? - person Austin; 09.03.2010
comment
Как именно разместить виджет в макете? Если вы вызываете A->addWidget(widget), то widget->layout() должен вернуть A. Если вы создаете виджет типа widget = new QWidget(A), тогда qobject_cast<QLayout*>(widget->parent()) должен вернуть A. - person Paul; 09.03.2010
comment
Я делаю A- ›addWidget (виджет). Я пробовал, и он возвращает нулевой указатель (0). Кроме того, widget = new QWidget (A) невозможен, поскольку макет не является QWidget, а конструктор QWidget принимает указатель на QWidget. - person Austin; 10.03.2010