Привязка аргументов к сигналам / слотам - PullRequest
10 голосов
/ 02 июля 2010

У меня в основном несколько сигналов событий, которые я хочу подключить к одному и тому же слоту.Я хочу знать, как я могу передать строковые параметры в тот же слот, чтобы слот знал, откуда поступает этот сигнал.Одна альтернатива состоит в том, чтобы создать столько временных интервалов, сколько имеется сигналов, и затем соединить их 1: 1, но это эффективно, учитывая, что код для всей обработки очень похож.Я пытался сделать это, но я получаю некоторые ошибки:

connect(selecter1,SIGNAL(selected(QString)),this,SLOT(backgroundTypeChoiceMade(QString)));
connect(button1,SIGNAL(clicked()),this,SLOT(backgroundTypeChoiceMade("button1")));
connect(button2,SIGNAL(clicked()),this,SLOT(backgroundTypeChoiceMade("button2")));

Ошибка связана с параметрами, которые я передаю в последних 2 командах .. И backgroundTypeChoiceMade объявляется так:

void backgroundTypeChoiceMade(QString);

Может кто-нибудь сказать мне, в чем ошибка в приведенном выше коде?

Ответы [ 6 ]

8 голосов
/ 29 мая 2012

Четыре метода.Один не сосет.

  1. QSignalMapper.Работает, но делает для грязного кода.
  2. Именованные слоты.Грязно для любого значительного числа отправителей и не работает для динамически генерируемых отправителей (например, кнопок в списке).
  3. sender() -сравнить.Может обрабатывать динамических отправителей, но все равно выглядит некрасиво.
  4. Подкласс отправителя .Не сосетДает вам то, что вы действительно хотели все время: параметризованные сигналы .

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

А теперь подключение сигналов и слотов просто работает:

Keypad::Keypad(QWidget *parent) : QWidget(parent)
{
    for (int i = 0; i < 10; ++i)
    {
        // KeypadButton keeps track of the identifier you give it
        buttons[i] = new KeypadButton(i, this);
        // And passes it as a signal parameter. Booyah.
        connect(buttons[i], SIGNAL(clicked(int)), this, SIGNAL(digitClicked(int)));
    }
    createLayout();
}

void Keypad::digitClicked(int digit)
{
    // The slot can find the clicked button with ease:
    dial(button[i]); // or whatever
    //...
}

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

См. http://doc.qt.digia.com/qq/qq10-signalmapper.html#thesubclassapproach для примера реализации подкласса QPushButton для излучения clicked(int) сигналов.Также обсуждаются все четыре метода - именованные слоты («тривиальное решение»), sender (), создание подклассов и отображение сигналов.

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

8 голосов
/ 02 июля 2010

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

5 голосов
/ 02 июля 2010

Что неэффективно в использовании отдельных слотов? Если в обработчиках слотов есть общность, переместите это в функцию, например, Пример расширения ereOn:

void YourClass::YourClass() :
  m_button1(new QPushButton()),
  m_button2(new QPushButton())
{
  connect(m_button1, SIGNAL(clicked()), this, SLOT(yourSlot1()));
  connect(m_button2, SIGNAL(clicked()), this, SLOT(yourSlot2()));
}

void YourClass::common(int n)
{
}

void YourClass::yourSlot1()
{
    common (1);
}

void YourClass::yourSlot2()
{
    common (2);
}
4 голосов
/ 02 июля 2010

Вы не можете передать константы connect(), потому что эффективные параметры выводятся во время выполнения, а не во время компиляции.

Однако, хотя это противоречит принципу OO, вы можете использовать QObject::sender() который дает указатель на излучатель QObject.

Пример ниже:

void YourClass::YourClass() :
  m_button1(new QPushButton()),
  m_button2(new QPushButton())
{
  connect(m_button1, SIGNAL(clicked()), this, SLOT(yourSlot()));
  connect(m_button2, SIGNAL(clicked()), this, SLOT(yourSlot()));
}

void YourClass::yourSlot()
{
  if ((QPushButton* button = dynamic_cast<QPushButton*>(sender()))
  {
    // Now button points to a QPushButton* that you can compare with the pointers you already have

    if (button == m_button1)
    {
      // Whatever
    } else
    if (button == m_button2)
    {
      // Whatever
    }
  }
}

Если у вас много кнопок, вы также можете использовать QSignalMapper , предоставивидентификатор для каждой кнопки.

0 голосов
/ 01 марта 2017

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

Пример:

connect(sender, &Sender::valueChanged,
    tr1::bind(receiver, &Receiver::updateValue, "senderValue", tr1::placeholder::_1));

См. больше информации .

Примечание: вы, конечно, можете использовать std :: bindили повысить :: связать вместо tr1 :: связать.

0 голосов
/ 14 декабря 2013

Если вы действительно не хотите использовать QSignalMapper, вы можете сделать что-то вроде этого:

class SignalForwarderWithString: public QObject
{
    Q_OBJECT
public:
    SignalForwarderWithString(QString data = "", QObject *parent = 0) : QObject(parent), _data(data) {}
    QString _data;
signals:
    void forward(QString);
public slots:
    void receive() { emit forward(_data); }
};

...
connect(selecter1,SIGNAL(selected(QString)),this,SLOT(backgroundTypeChoiceMade(QString)));

SignalForwarderWithString *sfws;
sfws = new SignalForwarderWithString("button1", this);
connect(button1,SIGNAL(clicked()), sfws, SLOT(receive(QString)));
connect(sfws, SIGNAL(forward(QString)), this,SLOT(backgroundTypeChoiceMade(QString)));

sfws = new SignalForwarderWithString("button2", this);
connect(button2,SIGNAL(clicked()), sfws, SLOT(receive(QString)));
connect(sfws, SIGNAL(forward(QString)), this,SLOT(backgroundTypeChoiceMade(QString)));

но QSignalMapper так же прост ...

QSignalMapper *mapper = new QSignalMapper(this);
connect(button1, SIGNAL(clicked()), mapper, SLOT(map()));
mapper->setMapping(button1, "button 1");
connect(button2, SIGNAL(clicked()), mapper, SLOT(map()));
mapper->setMapping(button2, "button 2");
// you might have to tweak the argument type for your slot...
connect(mapper, SIGNAL(mapped(const QString &), this, SLOT(backgroundTypeChoiceMade(QString)));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...