Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Nuclears от Июль 06, 2013, 21:47



Название: lambda функция слота clicked
Отправлено: Nuclears от Июль 06, 2013, 21:47
Итак, с совсем недавнего времени перешел на Qt, с++ не знаю совсем, вообщем очередное пополнение среди быдлокодеров :)
Перейдем к делу.

просто и элегантно это сделать в python:
Код:
self.Button.clicked.connect(lambda : self.SomeFunc(param))


Что же в Qt(с++):
Код:
//изврат же!
QObject::connect(ui->Button, &QPushButton::clicked, [=] (bool clicked) {
        if (!clicked) {
            this->SomeFunc(param);
        }
    });

Существует ли более изящный способ?
Нечто такое, которое естественно не работает, т.к. нет параметров у сигнала.
Код:
QObject::connect(this->ui->Button, SIGNAL(clicked()), this, SLOT(this->SomeFunc(param)));

ЗЫЖ Сигналмаппер опять же разрастание кода.

ЗЫЫЖ Кто не знает о lambda рекомендую:
http://woboq.com/blog/cpp11-in-qt5.html
Ну и Qt5 идет почти в ногу со временем :)
https://qt-project.org/wiki/New_Signal_Slot_Syntax


NB: Вопрос состоит в том, как просто и элегантно передать в слот параметры, при сигнале не имеющего параметров, а не в  "идеологии" этого процесса. Почитайте информацию по ссылкам, все встанет на свои места.


Название: Re: lambda функция слота clicked
Отправлено: lit-uriy от Июль 07, 2013, 01:09
Си++ это Си++
Пиши в его стиле. Сделай слот (функцию-член класса),  к нему и цепляйся.


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 09:20
Си++ это Си++
Пиши в его стиле. Сделай слот (функцию-член класса),  к нему и цепляйся.
Он такой же суровый как питон, не воспринимающий табуляцию :)
Неужели на каждое действие(однотипное с переменной) необходим свой слот? Конструкция с лямбдой у мну работает, но  вопрос в ее "изяществе" и поведении в исключительных ситуациях.
Да и новый тип сигнал/слот в qt5 тонко намекает, что использование лямбд упрощает жизнь и код :)


Название: Re: lambda функция слота clicked
Отправлено: lit-uriy от Июль 07, 2013, 14:07
>>новый тип сигнал/слот в qt5 тонко намекает, что использование лямбд упрощает жизнь и код
не согласен.
Приведённый тобою код на Си++ (нового стандарту) ниразу не понятен. Что там за проверка на "Не щёлкнули"? с чего тогда сигнал был послан?

>>Неужели на каждое действие(однотипное с переменной) необходим свой слот
На каждое событие (сигнал), а не на каждое действие.
Слот может быть и один, и в нём можно многое разруливать.

А вообще стоит подумать над имеющейся архитектурой, нужна ли функция SomeFunc вообще? Может лучше сделать подходящий слот?


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 15:40
>>Приведённый тобою код на Си++ (нового стандарту) ниразу не понятен. Что там за проверка на "Не щёлкнули"? с чего тогда  cигнал был послан?
Мой код лямбды не нового стандарта. bool clicked можно заменить на bool matumba, это просто лябда, и никакого отношения к сигналу не имеет.
Новый стандарт мну упомянул для примера, в котором нет функционала, когда сигнал не имеет параметров, а передать в слот нужно какой-то параметр.

>>На каждое событие (сигнал), а не на каждое действие.
>>Слот может быть и один, и в нём можно многое разруливать.
Именно это и пытаюсь сделать, создав один слот, в который можно передать параметр. А передать параметр можно только тогда, когда у сигнала он есть. Посмотри код внимательно, испытай код, сразу станет понятно.

>>А вообще стоит подумать над имеющейся архитектурой, нужна ли функция SomeFunc вообще? Может лучше сделать подходящий слот?
SomeFunc - это ни что иное как слот, по коду этого не видно?
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.


Название: Re: lambda функция слота clicked
Отправлено: m_ax от Июль 07, 2013, 16:11
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.

Идеология сигнально-слотового механизма (когда его придумывали) подразумевает, касательно описанного случая, следующее:
Когда кнопку "нажали", то ей вообще фиолетово, кто подписан на её сигнал "меня нажали".

Если логика вашего подхода требует по мимо этого, какие то дополнительные связи между сендером и рецийвером, то скорее всего - это  следствие похоспроектированной архитектуры.. То, о чём говорил lit-uriy

Потом, при объявлении лямды, она должна знать о вашем "param", что уже накладывает связь между сендером и получателем.. Что, в свою очередь, противоречить концепции сигнально-слотового механизма..

В идеале, ни тот, кто посылает сигнал, ни тот, кто его принимает, ничего не должен знать друг о друге. 

 


Название: Re: lambda функция слота clicked
Отправлено: kambala от Июль 07, 2013, 16:13
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.
упомянутый уже QSignalMapper; setObjectName() на крайний случай. С++ это не пайтон, смирись.


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 16:27
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.
упомянутый уже QSignalMapper; setObjectName() на крайний случай. С++ это не пайтон, смирись.
Прекрасно понимаю, что это классика C++, тем не менее лямбда из моего кода тоже функциональна.
Но кроме этих возможностей, может еще есть какие либо решения данной задачи? Неужели все дружно используют QSignalMapper? :)
Плодить код ради кода, меня такой подход в c++ настораживает :)


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 16:39
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.

Идеология сигнально-слотового механизма (когда его придумывали) подразумевает, касательно описанного случая, следующее:
Когда кнопку "нажали", то ей вообще фиолетово, кто подписан на её сигнал "меня нажали".

Если логика вашего подхода требует по мимо этого, какие то дополнительные связи между сендером и рецийвером, то скорее всего - это  следствие похоспроектированной архитектуры.. То, о чём говорил lit-uriy

Потом, при объявлении лямды, она должна знать о вашем "param", что уже накладывает связь между сендером и получателем.. Что, в свою очередь, противоречить концепции сигнально-слотового механизма..

В идеале, ни тот, кто посылает сигнал, ни тот, кто его принимает, ничего не должен знать друг о друге. 
 
Это и ежу понятно, что пофиг кто, есть факт создания сигнала.
Почему же сразу говорим "это  следствие похоспроектированной архитектуры" новому былдокодеру? :)
Представь таблицу в которой толпа строк, допустим 3 столбца, первый некое значение, второй некое значение, третий кнопка, при нажатии которой некое значение передаётся в слот, что-то исполнятся и таблица полностью перестраивается.
Классикой - сигнал маппер, отлавливаем и передаем в слот, принимающий уже от сигналмаппера значение.
Либо создать столько же слоток как и кнопок -> это уже, конечно, суицидальный метод.
Лямбдой же прямо в слот передаем значение, делаем что-то. В этом случаем мы пропускаем ненужный фильтр. Утрировано - экономим процессорное время.

При динамеском создании param берется опять же как и все остальные данные, из источника создания динамики. Это никак не нарушает концепцию. Создавая свой сигнал и слот, мы тоже нарушаем концепции? :)

Все это конечно ИМХО, возможно в скором будущем ко мне придет понимание того, что написать лишний код - это по феншую, но пока, мну другого мнения :)


Название: Re: lambda функция слота clicked
Отправлено: Igors от Июль 07, 2013, 16:44
просто и элегантно это сделать в python:

Что же в Qt(с++):
Код:
//изврат же!
Это чисто "вкусовое" ощущение (печать прошлого опыта), и оно быстро пройдет  :)


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 16:50
просто и элегантно это сделать в python:

Что же в Qt(с++):
Код:
//изврат же!
Это чисто "вкусовое" ощущение (печать прошлого опыта), и оно быстро пройдет  :)

Возможно :)
Т.е. это действительно самый "элегантный" способ, [теперь] знакомый сообществу http://www.prog.org.ru/ ?
Подожду еще, может кто наставит на путь истинный правильным, мотивированным предложением :)


Название: Re: lambda функция слота clicked
Отправлено: kambala от Июль 07, 2013, 16:54
Допустим динамически создаем 1000 кнопок, все они при клике должны передать в слот некий уникальный параметр, напиши пример такого коннекта без лямбды.
упомянутый уже QSignalMapper; setObjectName() на крайний случай. С++ это не пайтон, смирись.
Прекрасно понимаю, что это классика C++, тем не менее лямбда из моего кода тоже функциональна.
Но кроме этих возможностей, может еще есть какие либо решения данной задачи? Неужели все дружно используют QSignalMapper? :)
Плодить код ради кода, меня такой подход в c++ настораживает :)
еще один подход — создать хэш вида QHash<QPushButton *, K>, но от написания отдельного слота это не избавит. меньше всего символов уйдет на написание лямбды, но их тоже не нужно тулить сплошь и рядом: например если понадобится вызвать слот руками, то прозрачнее будет написать обычный вызов метода, чем загонять его сначала в лямбду, а потом уже вызывать ее.


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 17:07
...но их тоже не нужно тулить сплошь и рядом: например если понадобится вызвать слот руками, то прозрачнее будет написать обычный вызов метода, чем загонять его сначала в лямбду, а потом уже вызывать ее.
Почему же, при прямом вызове слота, параметр может быть пустым, что будет описано в самом слоте (проверка входящего параметра), т.е. это не требует написания ламбда функции -> дергать слот можем как и где угодно.


Название: Re: lambda функция слота clicked
Отправлено: kambala от Июль 07, 2013, 17:21
я имею в виду что если ты опишешь слот как лямбду, а не как метод, то придется заводить поле в классе для этой лямбды


Название: Re: lambda функция слота clicked
Отправлено: lit-uriy от Июль 07, 2013, 18:17
Плодить код ради кода, меня такой подход в c++ настораживает :)
Я вот вообще тебя не понимаю, на каждое соединение для тыщи кнопок тебя не напрягает плодить код (передава в лямбду параметра слота.
А использовать компактную запись с использованием QSignalMaper тебя напрягает.

Посмотри пример Калькулятор в поставке Qt там всё компактно


Название: Re: lambda функция слота clicked
Отправлено: lit-uriy от Июль 07, 2013, 18:25
Представь таблицу в которой толпа строк, допустим 3 столбца, первый некое значение, второй некое значение, третий кнопка, при нажатии которой некое значение передаётся в слот, что-то исполнятся и таблица полностью перестраивается.
вот давай о сути. Мне думается что если ты объяснишь некоторые подробности, то решение не заставит себя долго ждать.

как у тебя реализована таблица это представление или это виджет?

Если представление, то в делегате формирующем кнопку делаем один слот, он читает данные из нужного столбца своей строки (из модели), посылает заранее созданный сигнал имеющий параметр (в нём передаётся значение нужного столбца).
К этому сигналу ты и подключаешь свой слот SomeFunc(param)


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 19:05
я имею в виду что если ты опишешь слот как лямбду, а не как метод, то придется заводить поле в классе для этой лямбды
Нет, слот описывать как лямбду не зачем, мы же о лямбде в коннекте говорим :)

Плодить код ради кода, меня такой подход в c++ настораживает :)
Я вот вообще тебя не понимаю, на каждое соединение для тыщи кнопок тебя не напрягает плодить код (передава в лямбду параметра слота.
А использовать компактную запись с использованием QSignalMaper тебя напрягает.

Посмотри пример Калькулятор в поставке Qt там всё компактно
Зачем плодить, в цикле же генерация объектов, методов и параметров происходит :)
Смотрел на него только в поставке PySide, если не забуду гляну в Qt :)

Представь таблицу в которой толпа строк, допустим 3 столбца, первый некое значение, второй некое значение, третий кнопка, при нажатии которой некое значение передаётся в слот, что-то исполнятся и таблица полностью перестраивается.
вот давай о сути. Мне думается что если ты объяснишь некоторые подробности, то решение не заставит себя долго ждать.

как у тебя реализована таблица это представление или это виджет?

Если представление, то в делегате формирующем кнопку делаем один слот, он читает данные из нужного столбца своей строки (из модели), посылает заранее созданный сигнал имеющий параметр (в нём передаётся значение нужного столбца).
К этому сигналу ты и подключаешь свой слот SomeFunc(param)
На примере таблицы - виджет был. Про модель уже нашел отличный пример генерации модели с виджетами.
Но сути, пока, не поменяло, допустим условие другое: 1000 кликабельных QLabel, генерация динамическая, передача в слот параметра при сигнале clicked без сигналмаппера.

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


Название: Re: lambda функция слота clicked
Отправлено: kamre от Июль 07, 2013, 20:17
Может что-то не так понял, но чем не подходит вот такой вариант:
Код
C++ (Qt)
#include <QApplication>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
 
class Widget: public QWidget {
   QLabel *label;
public:
   Widget() {
       label = new QLabel("nothing");
       auto layout = new QVBoxLayout();
       layout->addWidget(label);
       const int n = 5;
       for (int i = 0; i < n; ++i) {
           auto button = new QPushButton(QString::number(i));
           layout->addWidget(button);
           connect(button, &QPushButton::clicked, [=] (bool) {
               setText(QString("button %1 clicked").arg(i));
           });
       }
       setLayout(layout);
   }
   void setText(const QString &text) {
       label->setText(text);
   }
};
 
int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   Widget widget;
   widget.show();
   return app.exec();
}
 


Название: Re: lambda функция слота clicked
Отправлено: kambala от Июль 07, 2013, 22:11
я имею в виду что если ты опишешь слот как лямбду, а не как метод, то придется заводить поле в классе для этой лямбды
Нет, слот описывать как лямбду не зачем, мы же о лямбде в коннекте говорим :)
твоя лямбда ведь и является по сути слотом (т.е. методом, который вызывается при нажатии на кнопку). вот если захочется тебе вызвать этот метод из другого места кода, то придется либо лямбду засовывать в переменную либо вызывать некрасивое button->click().

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

хэш-то чем не устроил (или objectName)? кода явно будет меньше чем при использовании сигналмаппера.

и кстати не надо забывать, что лямбды-слоты только в Qt 5 работают.


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 22:14
Может что-то не так понял, но чем не подходит вот такой вариант:

no matching function for call to 'Widget::connect(QPushButton*&, void (QAbstractButton::*)(bool), Widget::Widget()::<lambda(bool)>)'
Да и вообще в Qt5.0.2 сначала отказался компилироваться.


UPD: совсем забыл параметры компилятору дать :)
Код полностью исправен. Т.е. это действительно самый простой вариант для таких случаев?


Название: Re: lambda функция слота clicked
Отправлено: Nuclears от Июль 07, 2013, 22:30
я имею в виду что если ты опишешь слот как лямбду, а не как метод, то придется заводить поле в классе для этой лямбды
Нет, слот описывать как лямбду не зачем, мы же о лямбде в коннекте говорим :)
твоя лямбда ведь и является по сути слотом (т.е. методом, который вызывается при нажатии на кнопку). вот если захочется тебе вызвать этот метод из другого места кода, то придется либо лямбду засовывать в переменную либо вызывать некрасивое button->click().
А разве вызов метода click() объекта противоречит дзену ООП? Думал совсем наоборот :)

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

хэш-то чем не устроил (или objectName)? кода явно будет меньше чем при использовании сигналмаппера.

Честно, мну все еще плохо понимает типы данных C++ и создавать такие вещи просто пока не научился :)
и кстати не надо забывать, что лямбды-слоты только в Qt 5 работают.
Ну это понятно, к тому же мой вариант лямбды из C++11


Название: Re: lambda функция слота clicked
Отправлено: m_ax от Июль 07, 2013, 22:40

NB: Вопрос состоит в том, как просто и элегантно передать в слот параметры, при сигнале не имеющего параметров, а не в  "идеологии" этого процесса. Почитайте информацию по ссылкам, все встанет на свои места.

Курить в сторону std::bind? http://en.cppreference.com/w/cpp/utility/functional/bind (http://en.cppreference.com/w/cpp/utility/functional/bind)


Название: Re: lambda функция слота clicked
Отправлено: kamre от Июль 08, 2013, 15:36
это действительно самый простой вариант для таких случаев?
Можно еще вот так через std::bind:
Код
C++ (Qt)
#include <QApplication>
#include <QLabel>
#include <QLayout>
#include <QPushButton>
 
#include <functional>
 
int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
   auto label = new QLabel("nothing");
   auto layout = new QVBoxLayout();
   layout->addWidget(label);
   const int n = 10;
   for (int i = 0; i < n; ++i) {
       auto button = new QPushButton(QString::number(i));
       layout->addWidget(button);
       auto text = QString("button %1 clicked").arg(i);
       QObject::connect(button, &QPushButton::clicked,
                        std::bind(&QLabel::setText, label, text));
   }
   QWidget widget;
   widget.setLayout(layout);
   widget.show();
   return app.exec();
}