LINUX.ORG.RU

Как найти через findChild() член класса по QObject-имени?

 


0

2

У меня был класс с множеством объектов-кнопок. Эти объекты создавались динамически, то есть:

h-файл:

QToolButton *bold;
QToolButton *italic;
QToolButton *underline;

c++ файл:

QToolButton *bold=new QToolButton(this);
bold->setObjectName("editor_tb_bold");

QToolButton *italic=new QToolButton(this);
italic->setObjectName("editor_tb_italic");

QToolButton *underline=new QToolButton(this);
underline->setObjectName("editor_tb_underline");


Мне все твердят, что так делать ненада, нужно просто сделать кнопки членами класса, а не указатели на них. Я так и сделал:

h-файл:

QToolButton bold;
QToolButton italic;
QToolButton underline;

c++ файл:

bold.setObjectName("editor_tb_bold");

italic.setObjectName("editor_tb_italic");

underline.setObjectName("editor_tb_underline");


Кнопки нужно в рантайме повтыкать на панель инструментов в последовательности, настроенной пользователем. (Точнее, вставлять нужно не только кнопки, но и например выпадающие списки). Вставка происходит по имени вставляемого объекта.

Ранее, когда были указатели, метод вставки в панель инструментов выглядел так:

void EditorToolBar::insertButtonToToolsLine(QString toolName, QToolBar *line)
{
  if(toolName=="separator")
    line->addSeparator();
  else
  {
    QString name("editor_tb_"+toolName);
    QWidget *tool=this->findChild<QWidget *>(name);
    if(tool!=NULL)
    {
      tool->setVisible(true);
      line->addWidget(tool); // Инструмент добавляется на панель инструментов
 ...


Теперь, когда членами класса являются не указатели на виджеты, а сами виджеты, я не могу понять, как воспользоваться методом findChild().

В документации на этот метод ничего не сказано о том, что он не может работать с обычными объектами, а не с указателями:


T QObject::findChild(const QString & name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const

Returns the child of this object that can be cast into type T and that is called name, or 0 if there is no such object. Omitting the name argument causes all object names to be matched. The search is performed recursively, unless options specifies the option FindDirectChildrenOnly.

If there is more than one child matching the search, the most direct ancestor is returned. If there are several direct ancestors, it is undefined which one will be returned. In that case, findChildren() should be used.



Я пробовал получить указатель на член класса так:

QWidget *tool=this->findChild<QWidget *>(name);
QWidget *tool=&( qobject_cast<QWidget>( this->findChild<QWidget>(name) ) );
QWidget *tool=&( qobject_cast<QWidget>( &(this->findChild<QObject>(name)) ) );
QWidget *tool=qobject_cast<QWidget *>( &(this->findChild<QObject>(name)) );


Как я только не пробовал - ничего не получается.

Вопрос. Как заполучить указатель на член класса по QObject-имени объекта?

★★★★★

В твоем новом коде кнопки не являются чилдами объекта, так как ты не передаешь this в их конструкторы.

annulen ★★★★★
()

Добавлю к ответу annulen, что в Qt всегда стоит указывать предка — так меньше шансов забыть что-нибудь, ну и побочные эффекты оказываются чаще полезны (особенно для виджетов)

XMs ★★★★★
()

Перечитал твой тред (точнее, прочитал не по диагонали). Тех, кто говорит, что не надо использовать указатели, шли лесом и преспокойно используй.

Ещё, для того, что ты хочешь сделать, имена QObject-ов не нужны. Создавай слоты и проверяй через sender() — сравнение указателей всяко быстрее сравнения текста

XMs ★★★★★
()

Ты опять городишь какие-то дремучие костыли. Почитай исходники Qt что ли. Разницы между указателем и не-указателем по сути нет, все равно класс хранит указатель на объект приватного класса. У тебя опять все через задницу.

MuZHiK-2 ★★★★
()
Ответ на: комментарий от annulen

В твоем новом коде кнопки не являются чилдами объекта, так как ты не передаешь this в их конструкторы.

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

Добавил setParent(this), все заработало.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от XMs

Не, ты не понял.

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

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

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

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

Ясно. Это хорошо. А тогда зачем тебе child-ы?

XMs ★★★★★
()
Ответ на: комментарий от XMs

Ясно. Это хорошо. А тогда зачем тебе child-ы?

Просто я по текстовым именам распихиваю кнопки на панель.

Кнопки на панели находятся не статически, а конфигурируются пользователем. Одному нужна одна последовательность (набор) кнопок, второму другая. То есть, имеется просто список текстовых имен кнопок, в соответствии с ним кнопки на панель и засовываются.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Всё, теперь ясно.

Могу ещё посоветовать воспользоваться паттерном «пул объектов», чтобы не видимость менять, а непосредственно добавлять тогда, когда оно нужно. IMHO, так будет меньше заморочек с проблемой владения. А ещё сравнивать указатели не с NULL, а с nullptr

XMs ★★★★★
()
Ответ на: комментарий от XMs

В каком аспекте?

this:

что в Qt всегда стоит указывать предка — так меньше шансов забыть что-нибудь, ну и побочные эффекты оказываются чаще полезны
Ещё, для того, что ты хочешь сделать, имена QObject-ов не нужны. Создавай слоты и проверяй через sender() — сравнение указателей всяко быстрее сравнения текста

Без понимания того, что ты делаешь, эти советы скорее вредны, чем полезны.

UVV ★★★★★
()
Ответ на: комментарий от UVV

Без понимания того, что ты делаешь, эти советы скорее вредны, чем полезны

М. б., хотя я сходу не могу придумать ситуации, когда следование процитированному может обернуться каким-либо худом (за исключением того, что второе не подходит ТСу, как выяснилось впоследствии, тут мой совет действительно оказался вреден). Даже интересно, когда такое может быть

XMs ★★★★★
()
Ответ на: комментарий от XMs

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

По поводу sender:

Warning: This function violates the object-oriented principle of modularity. However, getting access to the sender might be useful when many signals are connected to a single slot.

Warning: As mentioned above, the return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.

UVV ★★★★★
()
Ответ на: комментарий от UVV

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

Соглашусь, хотя вреда от указания родителя не вижу — при ручном удалении предок будет уведомлён и при необходимости учтёт это. Разве что возможный оверхед (мало смысла указывать предка виджету, который будет помещён на layout), но он, IMHO, слишком незначителен по сравнению с возможной утечкой памяти, когда предок не был указан в следствие забывчивости, но подразумевалось автоматическое управление временем жизни средствами QObject.


Warning: This function violates the object-oriented principle of modularity

Любопытно. Интересно, чем же.


Warning: As mentioned above, the return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread

Случаи, когда подключение по DirectConnect объектов в разных потоках не является ССЗБ-измом, встречаются не слишком часто. Но да, этот аспект я не учёл

XMs ★★★★★
()
Ответ на: комментарий от XMs

Соглашусь, хотя вреда от указания родителя не вижу — при ручном удалении предок будет уведомлён и при необходимости учтёт это.

Ты не учёл обратный случай, когда удалён родитель, а дочерний QObject - он QObject всего лишь для того, чтобы поддерживать signal-slot, и который не надо удалять при удалении родителя.

UVV ★★★★★
()
Ответ на: комментарий от UVV

Действительно. Однако отношения «родитель—потомок» подразумевают иерархию, при которой потомок нужен только пока есть предок, в то время как в описанном примере объекты равноправны, а значит, не могут являться ни родителями, не потомками по отношению к друг другу (но при этом могут по отношению к другим объектам). Впрочем, в моём совете этот аспект не указан

XMs ★★★★★
()
Ответ на: комментарий от XMs

Впрочем, в моём совете этот аспект не указан

Я о чём и говорю. Нельзя просто так взять и написать писать категорично, без вдумчивости и учитывания деталей ;)

UVV ★★★★★
()
Ответ на: комментарий от UVV

Увы, не все нюансы задерживаются в памяти надолго — большинство вспоминается только в соответствующих ситуациях благодаря перекрёстным триггерам и ассоциациям (как указанное выше «владение—иерархия»). Поэтому, когда я пишу код, учитываю гораздо больше, чем когда даю советы (по крайней мере, пока какой-либо нюанс не будет встречаться столь часто, что таки запомнится)

XMs ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.