Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Узнать какой сигнал вызвал слот


Автор: borisbn 23.11.2011, 11:18
Привет.
Хочу узнать какой сигнал (не объект-сендер, а именно сигнал) вызвал слот.
Поясню: 
я коннекчу 2 сигнала одного объекта на один слот
Код

connect( &m_process, SIGNAL( readyReadStandardOutput() ), SLOT( onReadyRead() ) );
connect( &m_process, SIGNAL( readyReadStandardError() ), SLOT( onReadyRead() ) );

void CC::onReadyRead() {
    if ( вот_тут_хочу_узнать_кто_послал == readyReadStandardOutput() ) {
        setReadChannel( QProcess::StandardOutput );
    else
        setReadChannel( QProcess::StandardError );
    while ( m_process.canReadLine() ) {
        QString line = m_process.readLine()
        ...
    }
}

в onReadyRead() мне нужно узнать какой из сигналов дёрнул слот, чтобы сделать некоторые действия - а именно вызвать setReadChannel() с QProcess::StandardError или с QProcess::StandardOutput, а затем уже читать с помошью readLine().

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

connect( &m_process, SIGNAL( readyReadStandardOutput() ), SLOT( onReadyReadStd() ) );
connect( &m_process, SIGNAL( readyReadStandardError() ), SLOT( onReadyReadErr() ) );

void CC::onReadyReadStd() {
    setReadChannel( QProcess::StandardOutput );
    readFromProcess();
}
void CC::onReadyReadErr() {
    setReadChannel( QProcess::StandardError );
    readFromProcess();
}
void CC::readFromProcess() {
    while ( m_process.canReadLine() ) {
        QString line = m_process.readLine()
        ...
    }
}


Поэтому вопрос, скорее теоретический, чем жизненно необходимый.

Спасибо.

Автор: math64 23.11.2011, 14:31
В отладчике это можно увидеть в
this->QObject->currentSender->signal
(в виде индекса в таблице сигналов)
Но открытого доступа к этому полю нет (по крайней мере, я не нашёл)

Автор: alexvs11 23.11.2011, 14:39
почему не передавать в сигнал параметр?

Автор: borisbn 23.11.2011, 15:07
Цитата(alexvs11 @  23.11.2011,  14:39 Найти цитируемый пост)
почему не передавать в сигнал параметр?

потому, что это сигнал стандартного класса QProcess



Автор: Modul 23.11.2011, 15:15
типа такого:

Код

void CWidget::slotProg()
{
// номер потока
MyThread *t = (MyThread *)sender();
int x = t->getNumThread();  //номер потока
...
}


но тут надо имя метода...

Автор: borisbn 23.11.2011, 15:18
deleted, т.к. Modul уточнил smile

Автор: alexvs11 23.11.2011, 15:43
borisbn, параметр слота можно забить через QSignalMapper

Автор: borisbn 23.11.2011, 15:47
alexvs11, спасибо, ушёл курить QSignalMapper

Автор: Modul 23.11.2011, 15:47
может это поможет:

http://www.forum.crossplatform.ru/lofiversion/index.php/t2021.html


Код

void Test::testSlot()
{
    QObjectPrivate* sh = reinterpret_cast<QObjectPrivate*>(this->d_ptr);
    int idSignal = sh->currentSender->signal;
        QMetaMethod mm = (sender())->metaObject()->method( idSignal );
        const char *p = mm.signature();
    qDebug() << "Name of Signal" << p;
}


не проверял, но интересно!

Автор: borisbn 23.11.2011, 16:09
Modul, проверил. работает на версии 4.6.2. только чуть-чуть нужно подправить
Цитата
QObjectPrivate* sh = reinterpret_cast<QObjectPrivate*>(this->d_ptr.data());

.data() нужен потому, что тролли переделали хранение private-данных на QScopedPointer<QObjectData>, который может быть преобразован к QObjectData* только, если какая-нибудь ф-ция требует на вход QObjectData*, а reinterpret_cast не требует какого-то определённого указателя на вход.

В общем, этот способ меня в корне не устраивает, т.к. при смене версии Qt у меня программа в самом лучшем случае не скомпиляется, а в худшем - будет работать, и работать неправильно...

Автор: alexvs11 23.11.2011, 20:43
Код

void slotClass::onSignal(QString value) { qDebug() << value; }

void signalClass::signal() { emit emptySignal(); }


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    slotClass slot;
    signalClass s1, s2;
    QSignalMapper mapper;
    QObject::connect(&s1, SIGNAL(emptySignal()), &mapper, SLOT(map()));
    QObject::connect(&s2, SIGNAL(emptySignal()), &mapper, SLOT(map()));
    mapper.setMapping(&s1, "1");
    mapper.setMapping(&s2, "2");
    QObject::connect(&mapper, SIGNAL(mapped(QString)), &slot, SLOT(onSignal(QString)));

    s1.signal();
    s2.signal();

    return a.exec();
}


по-простому
можно конечно посмотреть код QSignalMapper - как он определяет кто послал сигнал

Автор: borisbn 24.11.2011, 08:35
alexvs11, 
Цитата(borisbn @  23.11.2011,  11:18 Найти цитируемый пост)
Хочу узнать какой сигнал (не объект-сендер, а именно сигнал) вызвал слот

для того, чтобы узнать сендера достаточно sender()

Автор: alexvs11 24.11.2011, 20:21
borisbn, ну разным сигналам задаете разные параметры
делов то

Автор: borisbn 24.11.2011, 20:59
Цитата(alexvs11 @  24.11.2011,  20:21 Найти цитируемый пост)
разным сигналам задаете разные параметры

alexvs11, покажите, как в Вашем коде с QSignalMapper это сделать
подозреваю - никак

Автор: math64 25.11.2011, 07:49
Можно сделать и через QSignalMapper - но в данном случае Ваш второй вариант из первого поста проще - фактически, при использовании QSignalMapper нужно в нём сделать то, что Вы сделали непосредственно в классе CC.

Автор: borisbn 25.11.2011, 08:33
Цитата(math64 @  25.11.2011,  07:49 Найти цитируемый пост)
Можно сделать и через QSignalMapper

разве что через разные QSignalMapper'ы...

Цитата(math64 @  25.11.2011,  07:49 Найти цитируемый пост)
при использовании QSignalMapper нужно в нём сделать то, что Вы сделали непосредственно в классе CC

дико извиняюсь, что туплю, но... как ?

Автор: math64 25.11.2011, 10:52
Я имел в виду не использовать стандартный QSignalMapper, а написать собственный по его образу.  Если нужно применять несколько раз, это оправдано.
Или использовать два стандартных QSignalMapper, как Вы предложили.

Автор: borisbn 25.11.2011, 13:13
Не, пожалуй, сегодня не мой день. Всё равно не пойму как это сделать. Если как-то так
Код

void CC::onReadyRead( int signalIdx ) {
    if ( signalIdx == 1 )
      ...
   дальше понятно
}

MySignalMapper m_mapper;

CC::СС() {
    connect( &m_process, SIGNAL( readyReadStandardOutput() ), &m_mapper, SLOT( onSignal1() ) );
    connect( &m_process, SIGNAL( readyReadStandardError() ), &m_mapper, SLOT( onSignal2() ) );
    connect( &m_mapper, SIGNAL( onSignal( int ) ), SLOT( onReadyRead( int ) ) );
}

class MySignalMapper {
public slots:
  void onSignal1() { emit onSignal( 1 ); }
  void onSignal2() { emit onSignal( 2 ); }
signals:
  void onSignal( int );

то это, действительно, не отличается от моего варианта №2, причём, при изменении количества сигналов или их сигнатуры, придётся менять этот "унивирсальный" MySignalMapper.

В общем, повторюсь: проблема уже решена, и это был чисто теоретический вопрос...
Закрываю.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)