Russian Qt Forum
Ноябрь 25, 2024, 06:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Связать число со слотом.  (Прочитано 14523 раз)
Eugene Efremov
Гость
« : Сентябрь 02, 2008, 02:12 »

Есть класс QSignalMapper, позволяющий превратить сигнал в строку или число. Как решать обратную задачу — связать слот с произвольной строкой или числом? В идеале хочется примерно такого:
Код:
enum MyEnum {Foo, Bar, Baz ....};
...

connect(this, Foo, other, SLOT(fooAction()));
...

void callSomeActions(MyEnum t)
{
    emit t;
}

Макросы  SIGNAL и SLOT преобразуют имя ф-ции именно в строку, так что сделать что-то похожее должно быть достаточно легко... Но сходу ответ найти не получилось...


P.S. Если не связываться с сигналами/слотами, то реализовать что-то похожее можно примерно так:

Код:
class caller_base
{
public:
virtual void call() = 0;
virtual ~caller_base() {}
};

template<class type> class caller : public caller_base
{
type *ptr;
void (type::*fun)();

public:
caller(type *p,  void (type::*f)()) : ptr(p), fun(f) {}

virtual void call()
{
(ptr->*fun)();
}
};

enum MyEnum {Foo, Bar, Baz};

QHash<int, caller_base *> hash;

template <class type>
void myConnect(MyEnum t, type *ptr, void (type::*fun)())
{
hash[t] = new caller<type>(ptr, fun);
}

void myEmit(int i)
{
if(hash.contains(i)) hash[i]->call();
}


Но раз уже существует готовый — и очень похожий — механизм, то соблазнительно использовать именно его, а не городить самодельные огороды...

P.P.S. Да, на всякий случай: switch/case не предлагать! :-)
« Последнее редактирование: Сентябрь 02, 2008, 02:50 от Eugene Efremov » Записан
Tonal
Гость
« Ответ #1 : Сентябрь 02, 2008, 08:01 »

Ну а прчему переходник/диспетчер не сделать?
Который будет слушать интересующий сигнал, и дёргать подписанные объекты?
Можно и с применением шаблонов и без. Улыбающийся
Записан
spirit
Гость
« Ответ #2 : Сентябрь 02, 2008, 09:34 »

или же заюзать QSignalMapper.
Записан
Eugene Efremov
Гость
« Ответ #3 : Сентябрь 02, 2008, 15:41 »

Ну а прчему переходник/диспетчер не сделать?
Который будет слушать интересующий сигнал, и дёргать подписанные объекты?
Не понял. Зачем мне слушать сигнал? Мне его сгенерить надо. На основе числа.

или же заюзать QSignalMapper.
Люди, вы читать умеете? Я же русским языком написал: требуется операция, обратная по отношению к той, которую обеспечивает QSignalMapper.
Не из сигнала получить число, а наоборот.
Записан
Alex03
Гость
« Ответ #4 : Сентябрь 03, 2008, 06:42 »

Давайте по порядку...
Вам надо:
1. именно генерить РАЗНЫЕ сигналы в зависимости от значения enum-а?
2. Вызывать определённые слоты определёных (заранее известных) объектов в зависимости от значения enum-а?
3. что то ещё?

Цитировать
P.P.S. Да, на всякий случай: switch/case не предлагать! :-)
Для первых 2-х случаев switch/case думаю будет оптимальным как по размеру кода дак и по скорости.
В случае enum-а без дырок можно ещё просто массив указателей на сигналы сделать... (впрочем оптимизирующие компиляторы тоже не дремлют и switch/case оптимизировать умеют, т.е. не делают длинных цепочек if ... else if ... else if ... else)

Ну и ИМХО шаблоны приведённые - хорошо, но несколько запутыват, для разных используемых типов в шаблоне генерится свой код функций и т.д.
Записан
ритт
Гость
« Ответ #5 : Сентябрь 03, 2008, 06:55 »

храни в массиве или хэше сигнатуру сигнала и зови invokeMethod
рекомендую посмотреть исходники, генерируемые moc'ом
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #6 : Сентябрь 03, 2008, 15:14 »

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

Юра.
Eugene Efremov
Гость
« Ответ #7 : Сентябрь 03, 2008, 19:24 »

храни в массиве или хэше сигнатуру сигнала и зови invokeMethod
рекомендую посмотреть исходники, генерируемые moc'ом

О. Вот это именно то, что нужно. Спасибо!

Теперь попробую ответить тем, кто «что-то не понял»:
Задача простейшая и весьма часто встречающаяся в самых разных контекстах: требуется предпринимать разные действия в зависимости от различных значений некой величины. Недостатки традиционного решения через switch/case перечислять не буду: это и до меня делалось неоднократно, если кто все еще считает этот вариант наилучшим, чтож — его право. Я так не считаю.

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

Остается одно — хеш (в простейшем случае — массив), связывающий множество значений этой величины с множеством неких функторов. А касательно того, что это за функторы — тут возможны варианты... Простейший — с указателями на методы — имеет одну проблему: в языке не предусмотрено безопасное приведение (например, с помощью dynamic_cast) указателей на члены производных классов в указатели на члены базовых. Значит, если нам такое приведение понадобится (а оно понадобится) — придется извращаться.

Вариант с шаблонами, который я привел в первом постинге, решает эту проблему. И его хватает почти во всех случаев, если только нам не требуется масштабировать задачу на случай множества функторов с разным количеством и типом аргументов. Чтобы решить — если нужно —  эту проблему, уже придется пользоваться бустом или еще чем в том же роде...

Вот примерно так это разруливатеся. Если с решать с нуля.
А теперь обращаем внимание на то, что в Qt это все уже решено, причем для самого общего случая и в наиболее гибкой форме — в механизме слот-сигнального взаимодействия. И задается вопросом: а нельзя ли, вместо того, чтобы весь вышеописанный огород городить, заюзать для своих нужд этот — уже готовый и отлично работающий — механизм...

Вот об том этот тред и был. Спасибо за внимание, все свободны! Подмигивающий
Записан
ритт
Гость
« Ответ #8 : Сентябрь 03, 2008, 19:40 »

нахожу последний пост несколько помпезным...

фактически invokeMethod использует кучу if и switch/case
разница с самопальной реализацией лишь в том, что в родной требуется только определить метаобъект, а самопальную нужно ещё придумать и написать Улыбающийся
Записан
Eugene Efremov
Гость
« Ответ #9 : Сентябрь 03, 2008, 20:48 »

фактически invokeMethod использует кучу if и switch/case

Хм... Посмотрел <qt>/src/corelib/kernel/qmetaobject.cpp — ни одного switch/case во всем файле.  Улыбающийся
А что их moc использует — ну дык он робот, ему можно. Подмигивающий

в родной требуется только определить метаобъект, а самопальную нужно ещё придумать и написать Улыбающийся

О том и речь...
Записан
ритт
Гость
« Ответ #10 : Сентябрь 03, 2008, 23:39 »

рекомендую посмотреть исходники, генерируемые moc'ом

будем считать тему закрытой
Записан
Eugene Efremov
Гость
« Ответ #11 : Сентябрь 04, 2008, 00:15 »

А что их moc использует — ну дык он робот, ему можно.
Записан
ритт
Гость
« Ответ #12 : Сентябрь 04, 2008, 00:53 »

moc их не использует, moc их генерирует Улыбающийся

иожно, конечно, и пофлудить...не забыть бы потом ветку подчистить
Записан
Alex03
Гость
« Ответ #13 : Сентябрь 04, 2008, 07:27 »

Не спора ради.

Теперь попробую ответить тем, кто «что-то не понял»:
Задача простейшая и весьма часто встречающаяся в самых разных контекстах: требуется предпринимать разные действия в зависимости от различных значений некой величины. Недостатки традиционного решения через switch/case перечислять не буду: это и до меня делалось неоднократно, если кто все еще считает этот вариант наилучшим, чтож — его право. Я так не считаю.
Эт видимо камень в мой огород. Я не считаю switch/case наилучшим во всех случаях, но в ряде случаев применение этой конструкции вполне оправдано. В частности для исходного примера с enum MyEnum {Foo, Bar, Baz ....}; т.е. тогда когда "некая величина" принимает конечное, заранее известное, и, желательно небольшое количество значений.

В ряде других случаев, в том числе когда нужно динамическое назначение неких функторов для некой величины - да switch/case не катит. Но этих случаев гораздо меньше.


invokeMethod() тут тоже не самый лучший (оптимальный по производительности) вариант ибо работает со строковыми литералами, генерит строку типа "methodName(type1,type2)", получает из неё индекс метода (QMetaObject::indexOfMethod()) простым банальным strcmp() в циклах по именам методов (сигналов и слотов) объектов в иерархии, и в конце концов вызывает qt_metacall() (в случае с Qt::DirectConnection)
Т.е. было бы оптимальней хранить в хэше не сигнатуру сигнала/слота (в обшем случае метода), а индекс метода (QMetaObject::indexOfMethod()) и вызывать qt_metacall() напрямую, вот только qt_metacall() не документирован у троллей, и вполне могут чтото поменят в будущем. Грустный


PS А недостатки switch/case не плохо было бы послушать, вдруг чего не знаю. Серьёзно.
Записан
Tonal
Гость
« Ответ #14 : Сентябрь 04, 2008, 08:57 »

Я использую хеш с функторами, если разных значений >2 но мне это проще, т.к. я пишу в основном на python-е, а там и функтор и хеш в язык встроены.
Т.е. используешь не задумываясь. Улыбающийся

Хотя таких ситуаций у меня довольно мало...
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.108 секунд. Запросов: 23.