Russian Qt Forum

Qt => Общие вопросы => Тема начата: QCasper от Апрель 16, 2008, 17:27



Название: signal mapping
Отправлено: QCasper от Апрель 16, 2008, 17:27
Есть класс С1, у него есть два сигнала A и B без параметров. Требуется, чтобы по этим сигналам вызывались слоты A и B соответственно класса C2. Слоты класса С2 примают в качестве параметра int. Я посмотрел QSignalMapper, но, насколько я понял, с помощью него нельзя сделать так чтобы, один сигнал маппировался на один слот, а второй на другой.


Название: Re: signal mapping
Отправлено: pastor от Апрель 16, 2008, 17:38
сделайте для слотов класса C2 параметры по умолчанию. Должно работать. Т.е. будет что -то вроде этого

Код:
class С1
{
signals:
    void A();
    void B();
};

class С2
{
public slots:
    void A(int param = 0);
    void B(int param = 0);
};

....

connect(c1, SIGNAL(A()), c2, SLOT(A()));
connect(c1, SIGNAL(B()), c2, SLOT(B()));


Название: Re: signal mapping
Отправлено: QCasper от Апрель 16, 2008, 21:57
Прошу прощения, я не совсем удачно сформулировал вопрос. Допустим, что в классе С2 у меня один единственный слот с параметром типа int. Класс С1 имеет кучу сигналов: S1, S2, ... , Sn без параметров. Так вот мне нужно маппировать эти сигналы на слот класса С2 таким образом, чтобы в зависимости от сигнала S1, S2, ... или Sn, этот слот вызывался со значением параметра 1, 2, ... n соответственно.


Название: Re: signal mapping
Отправлено: Вячеслав от Апрель 16, 2008, 22:35
А влоб - сделать еще один слот с параметром , а там switch'ем  звать кого надо ?
Все другое - IMHO будет еще веселее.....
QSignalMapper делает обратное  - собирает кучу простык сигналов в один ( с параметром) ....


Название: Re: signal mapping
Отправлено: QCasper от Апрель 16, 2008, 23:15
Что делает QSignalMapper мне как раз понятно.
А switch это аццкое зло. Пример приведите, пожалуйста, если можно.


Название: Re: signal mapping
Отправлено: Sergeich от Апрель 17, 2008, 02:07
Через стандартное API кутехи этого сделать нельзя. Можно в слоте узнать объект от которого поступил сигнал ( через QObject::sender, на этом и построен QSignalMapper ), но нельзя узнать имя имя сигнала. Нужен метод типа
const char* QObject::signal() . Отпишись троллям, возможно они это сделают (через полгода :) ).
Как вариант: заведи в классе эмитирующем сигнал переменную типа int и перед эмитированием вставляй в ней нужное значение:
Код:
signalId = THIS_SIGNAL_ID;
emit thisSignal();
Потом в слоте
Код:
Mapper::onSignal() 
{
  Emitter* e = qobject_cast<Emitter*> sender();
  if (e) {
    int id = e->getSignalId();
    // emit blabla(id);
   // c2->slot(id);
   // invoke...... etc 
 }
}


Название: Re: signal mapping
Отправлено: Sergeich от Апрель 17, 2008, 02:27
Кстати, довольно интересная тема по поводу модели сигнал - слот. Действительно, если я могу спросить: -кто?
почему я не могу спросить:  -какого хуя? :)


Название: Re: signal mapping
Отправлено: Alex03 от Апрель 17, 2008, 07:49
QCasper, а мне интересно зачем тебе это надо?
Приведи пример какойнить, можно абстрактный.


Название: Re: signal mapping
Отправлено: Tonal от Апрель 17, 2008, 08:26
В PyQt это делается элементарно:
Код:
class C2:
  def connect2C1(self, c1):
    def gen_wrap(i):
       return lambda: self.slot(i)
    for i, signal in enumerate(('S1', 'S2', ... , 'Sn')):
       self.connect(c1, QtCore.SIGNAL(signal), gen_wrap(i))
Здесь с1 - объект класса С1.
В цикле выполняется связывание перечисленных сигналов с переходником который вызывает нужный нам слот С2.slot с порядковым номером сигнала.

Как это сделать на С++ что-то в голову не приходит.
Разве что хакнуть тот QMetaObject что генерится moc-ом...


Название: Re: signal mapping
Отправлено: QCasper от Апрель 17, 2008, 09:04
QCasper, а мне интересно зачем тебе это надо?
Приведи пример какойнить, можно абстрактный.


Например для следующего. Системе требуется переключаться между состояниями. То есть существует метод setState(int state). Система должна переключаться между состояниями не просто так, а в ответ на возникновение некоторого события. Существует таблица (конфигурируемая), которая описывает зависимость состояний от событий. То есть грубо говоря это ассоциативный массив где событие ключ, а состояние -  значение. То есть эти сигналы, которые емитятся классом С1 это и есть те самые события и они и должны маппироваться в некий слот подобного содержания:

Код:
void setStateByEvent(int event) {
     setState(m_States[event]);
}

где m_States - та самая таблица.

Кстати, довольно интересная тема по поводу модели сигнал - слот. Действительно, если я могу спросить: -кто?
почему я не могу спросить:  -какого хуя? :)

во во :)


Название: Re: signal mapping
Отправлено: Tonal от Апрель 17, 2008, 10:31
Нашел! :-)
Можно использовать обработку событий.
В Qt, при асинхронном сигнале посылается событие QMetaCallEvent QEvent::MetaCall.
У него есть id - индекс вызываемого.

Идея такая - для коннекта используем QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type = 0, int *types = 0);
Где type = Qt::QueuedConnection, а method_index - наш номер состояния
Далее ловим событие QMetaCallEvent и вызываем обработчик с параметром. :-)

Единственное, что всё это - недокументированные потроха, так что при смене версии Qt можно нарваться. :)

P.S. Корректное использование QMetaObject::connect см. в QObject::connect.

P.P.S. Может всё же через сообщения напрямую это замутить? Попроще выёдет. :)


Название: Re: signal mapping
Отправлено: QCasper от Апрель 17, 2008, 12:26
P.P.S. Может всё же через сообщения напрямую это замутить? Попроще выёдет. :)

Это как? :)


Название: Re: signal mapping
Отправлено: Tonal от Апрель 17, 2008, 13:13
Вместо генерации сигналов кидать сендом или постом своего наследника QEvent.
Ну и обрабатывать его как тебе требуется. :)


Название: Re: signal mapping
Отправлено: Вячеслав от Апрель 17, 2008, 19:40
1) Народ , а давайте плиз без командного диалекта  языка ( какого .....)
2) Если слот позвали, а параметров у него нет - то и нефиг знать _почему_ его позвали.Иначе - ошибка проектирования IMHO
3)
Код:
class С2
{
public slots:
    void A(int param = 0);
    void B(int param = 0);
    void Common(int);
};

void C2::Common(int why)
{
switch(why)
 case valueA : A();break;
 case valueB : B();break;
default : errorHandler(why);
}
Ну тоже что делает metacall только сам ;)


Название: Re: signal mapping
Отправлено: QCasper от Апрель 17, 2008, 20:18
2) Если слот позвали, а параметров у него нет - то и нефиг знать _почему_ его позвали.Иначе - ошибка проектирования IMHO

Не совсем понятно к чему это.

Код:
class С2
{
public slots:
    void A(int param = 0);
    void B(int param = 0);
    void Common(int);
};

void C2::Common(int why)
{
switch(why)
 case valueA : A();break;
 case valueB : B();break;
default : errorHandler(why);
}

И это.


Название: Re: signal mapping
Отправлено: Вячеслав от Апрель 17, 2008, 20:25
Млин :( Нефиг в паралель с ДСП возиться ;(( Стормозил ....
Тогда уже ответили на поставленный вопрос - параметр по умолчанию ;)

Вторая ремарка была ответом на реплику  "почему нельзя узнать какого х.. позвали слот" .....


Название: Re: signal mapping
Отправлено: QCasper от Апрель 17, 2008, 20:57
Млин :( Нефиг в паралель с ДСП возиться ;(( Стормозил ....
Тогда уже ответили на поставленный вопрос - параметр по умолчанию ;)

Вторая ремарка была ответом на реплику  "почему нельзя узнать какого х.. позвали слот" .....

Да и параметр по умолчанию вобщем-то тоже уже не в тему. Почитайте посты повнимательнее.


Название: Re: signal mapping
Отправлено: Sergeich от Апрель 18, 2008, 13:39
Класс, отслеживающий испускание сигналов объектом. Параметр в сигнале emitted - идетификатор сигнала, который можно использовать в QMetaObject::method(int)
sigwatcher.h:
Код:
#ifndef SIGNAL_WATCHER
#define SIGNAL_WATCHER

#include <QObject>

class SignalWatcher : public QObject
{
Q_OBJECT
public:
SignalWatcher( QObject* obj );
private slots:
void dummy();
signals:
void emitted(int);
private:
bool event( QEvent* e );
QObject* wObj;
};

#endif // SIGNAL_WATCHER
sigwatcher.cpp:
Код:
#include "sigwatcher.h"
#include <QEvent>
#include <QMetaMethod>

#include <qobject_p.h> // hmmm... you can find it in $QTDIR/src/corelib/kernel

SignalWatcher::SignalWatcher( QObject* obj )
: QObject(obj), wObj(obj)
{
const QMetaObject* mo = wObj->metaObject();
int n = mo->methodCount();
for ( int i = 0; i < n; i++ ) {
QMetaMethod meth = mo->method(i);
if ( meth.methodType() == QMetaMethod::Signal ) {
    QByteArray sign = "0";
    sign[0] = sign[0] + QSIGNAL_CODE;
    sign += meth.signature();
    connect( wObj, sign, this, SLOT(dummy()), Qt::QueuedConnection );
}
}
}

bool SignalWatcher::event( QEvent* e )
{
if ( e->type() == QEvent::MetaCall ) {
QMetaCallEvent* me = (QMetaCallEvent*) e;
int sigId = me->signalIdStart();
emit emitted(sigId);
//debug
const QMetaObject* mo = wObj->metaObject();
QMetaMethod meth = mo->method(sigId);
qDebug("Signal %s emitted", meth.signature() );
//-----
return true;
}
return false;
}

void SignalWatcher::dummy()
{
}


Название: Re: signal mapping
Отправлено: QCasper от Апрель 20, 2008, 11:33
Ужасы какие  :o
Я решил пойти несколько другим путем:

signalmapper.h:

Код:
class SignalMapper : public QObject {
Q_OBJECT
public:
SignalMapper(QObject *parent = 0):QObject(parent) {}

void setMapping(QObject *object, const char *signal, int id);

signals:
void mapped(int id);

private:
QSignalMapper* freeMapper(QObject *object);

QMultiMap<QObject*, QSignalMapper*> m_SignalMappers;
};

signalmapper.cpp:

Код:
void SignalMapper::setMapping(QObject *object, const char *signal, int id) {
QSignalMapper *mapper = freeMapper(object);
connect(object, signal, mapper, SLOT(map()));
mapper->setMapping(object, id);
}
QSignalMapper* SignalMapper::freeMapper(QObject *object) {

QList<QSignalMapper*> mappers = m_SignalMappers.values();
for (int i=0; i<mappers.size(); i++) {
if (!m_SignalMappers.keys(mappers[i]).contains(object)) {
m_SignalMappers.insert(object, mappers[i]);
return mappers[i];
}
}

QSignalMapper *mapper = new QSignalMapper(this);
m_SignalMappers.insert(object, mapper);

connect(mapper, SIGNAL(mapped(int)), SIGNAL(mapped(int)));

return mapper;
}

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


Название: Re: signal mapping
Отправлено: EhTemka от Май 05, 2008, 22:52
Прошу прощения, я не совсем удачно сформулировал вопрос. Допустим, что в классе С2 у меня один единственный слот с параметром типа int. Класс С1 имеет кучу сигналов: S1, S2, ... , Sn без параметров. Так вот мне нужно маппировать эти сигналы на слот класса С2 таким образом, чтобы в зависимости от сигнала S1, S2, ... или Sn, этот слот вызывался со значением параметра 1, 2, ... n соответственно.

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


Название: Re: signal mapping
Отправлено: QCasper от Май 06, 2008, 00:12
Прошу прощения, я не совсем удачно сформулировал вопрос. Допустим, что в классе С2 у меня один единственный слот с параметром типа int. Класс С1 имеет кучу сигналов: S1, S2, ... , Sn без параметров. Так вот мне нужно маппировать эти сигналы на слот класса С2 таким образом, чтобы в зависимости от сигнала S1, S2, ... или Sn, этот слот вызывался со значением параметра 1, 2, ... n соответственно.

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

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


Название: Re: signal mapping
Отправлено: EhTemka от Май 06, 2008, 16:06
с каждым сигналом Sn вываливать еще и сигнал со значением n

в сигналах Sn вообще нет никакой необходимости, так как они заменяются на сигнал S(int n)

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

С этим не поспоришь ;)


Название: Re: signal mapping
Отправлено: QCasper от Май 08, 2008, 20:39
с каждым сигналом Sn вываливать еще и сигнал со значением n

в сигналах Sn вообще нет никакой необходимости, так как они заменяются на сигнал S(int n)

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