LINUX.ORG.RU

[Qt] Иерархия и сигналы-слоты

 


0

1

Вот у меня есть MainWindow. Там лежит вью, у вью есть сцена. Там же есть док, в доке куча всякой фигни.

Где-то в глубине дока может появляться виджет. Причём так как он появляться может в разных местах (или в виде диалога, или в виде встроенного), то и и пэрент у него может разниться. Этот виджет слёт сигналы, которые должна получать сцена.

Где и как идеологически правильно сигнально-слотово связывать такой виджет со сценой?

★★★★★

Как вариант в конструкторе виджета: передавать ему указатель на сцену

anonymous
()

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

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

> Создать отдельный класс-коммутатор, который будет соединять сигналы и слоты.

Хм... как такое реализовать? Если виджет динамически создаётся только когда надо.

Obey-Kun ★★★★★
() автор топика

Скажу, как у меня сделано сейчас.

В MainWindow есть функция Scene *qfScene(), возвращающая указатель на сцену. Объект мой может представать или просто виджетом (при этом родитель — дочка мейнвиндова в 3 поколении), либо в качестве дочки диалога.

В конструкторе этого виджета я делаю необходимые коннекты со сценой примерно таким образом:

MainWindow *m = static_cast<MainWindow *>(parent->parent()->parent())
connect(m->qfScene(), SIGNAL(selectionChanged(bool)),this, SLOT(updateButtons(bool))
 

Ну если я создаю диалог с этим виджетом, то я пользуюсь тем, что диалог можно создавать в принципе с любым пэрентом. И я создаю его с таким пэрентом, чтобы получилось, чтобы его пэрентом в 3 поколении оказалось главное окно. Так-то.

Коряво, но ничего другого в голову не пришло, вот и создал тему.

Obey-Kun ★★★★★
() автор топика

Я бы сделал метод Widget::setScene(QGraphicsScene * scene), в котором бы и связывал виджет со сценой.

rival ★★
()
Ответ на: комментарий от Obey-Kun

Да, так получше, ибо обременять конструкторы кучей аргументов (по идеологии Qt) — плохо.

Это, конечно, тоже. Но меня смутил вот этот код:

MainWindow *m = static_cast<MainWindow *>(parent->parent()->parent())
connect(m->qfScene(), SIGNAL(selectionChanged(bool)),this, SLOT(updateButtons(bool))
Если бы я делал через конструктор, то тогда бы уж передавал сразу указатель на сцену.

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

Код выше — пример, у меня оно страшнее. Вот копипаста прямо из проекта.

void SoilsWidget::newSoil()
{
    QUndoStack *stack = static_cast<MainWindow*>(parent()->parent()->parent()->parent()->parent())->undoStack();
    stack->beginMacro(tr("Create and edit soil"));
    m_original_soils_model->createNewSoil();
    SoilEditDialog add_dialog(m_original_soils_model, -1, this);
    add_dialog.exec();
    stack->endMacro();
    
    if(add_dialog.result() == QDialog::Rejected) {
        //FIXME: suxx till QTBUG-15764 will become fixed
        stack->undo();
    }
}

Правда, данная копипаста непосредственно с сигналами-слотами не связана. Но к вопросу имеет прямое отношение. Видится два решения:

1. Оставить всё как есть. Ведь всё работает.

2. Добавить функцию setMainWindow(), которая делала бы нужные коннекты и запоминала указатель на главное окно в приватное поле (чтобы этот указатель использовать в местах типа того, что я только что привёл).

Склоняюсь ко второму варианту, т.к. так код станет понятнее и сложней будет ошибиться.

Obey-Kun ★★★★★
() автор топика

Уважаемые, очень странно, что до сих пор никто не упомянул ни findChild, ни findChildren, ни connectSlotsByName… А ведь это, по-моему, очень удобное и хорошее решение.

Obey-Kun ★★★★★
() автор топика

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

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

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

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

> Уважаемые, очень странно, что до сих пор никто не упомянул ни findChild, ни findChildren, ни connectSlotsByName… А ведь это, по-моему, очень удобное и хорошее решение.

Тьфу, не годится, ведь чилд-то динамически создаётся. Вот был бы findparent :)...

Obey-Kun ★★★★★
() автор топика

Пришло в голову 3 сумасшедших идеи. Они помогут забыть о головной боли из-за поиска MainWindow.

Идея 1. Функция template<typename T> T findNearestParent(). Делает вложенный parent() до тех пор, пока qobject_cast<T> для полученного объекта станет не NULL. Таким образом, можно находить, скажем, MainWindow, в котором находится виджет.

Идея 2. Функция findNearestObjectByName(const QString &name). Делает parent(). Там делает findchild(name). Не нашло — идёт выше в иерархии объектов. Пока не найдёт. Эта штука нелепа, но почему-то тоже пришла в голову.

Идея 3. Статический член MainWindow *main_win в MainWindow. В конструкторе MainWindow делается main_win = this. Всё бы хорошо, но но это позволяет иметь только одно главное окно в одной инстанции программы.

Что скажете насчёт идей 1 и 3?

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

В дзене питоновода очень хорошие правила написаны. (Сам питон не использую). ИМХО им следовать должен любой уважающий себя программист. Так вот:

Явное лучше, чем неявное. Простое лучше, чем сложное. Читаемость имеет значение. Если реализацию сложно объяснить — идея плоха.

А теперь посмотри на свои костыли с этой точки зрения и сравни его с моим предложенным решением (первом пост).

anonymous
()
Ответ на: комментарий от Obey-Kun

>> Создать отдельный класс-коммутатор, который будет соединять сигналы и слоты.

Хм... как такое реализовать? Если виджет динамически создаётся только когда надо.


Я это вижу так: создаешь класс-синглтон (если MainWindow всего один), который содержит слоты рассылки сигналов. Т.е. каждый его слот просто высылает соответствующий сигнал.

Далее к сигналам коммутатора цепляешь сцену, а создаваемые доки цепляешь к слотам коммутатора. Если различных сигналов-слотов не много, то все ок.

trex6 ★★★★★
()
Ответ на: комментарий от Obey-Kun

> Пришло в голову 3 сумасшедших идеи.

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

есть же QWidget::nativeParentWidget()

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

ХЗ где можно про это почитать =) В википедии можно, в принципе.

В целом это комбинация синглтона и, например, обсервера наоборот.

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

не то, ибо если виджет в диалоге, то оно указывает на диалог.

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