Как работает QSignalMapper?

После моего сообщения здесь: Связать сигнал и слот с qcheckbox создается динамически Мне нужно связать:

• Сигнал clicked(), когда я нажимаю qCheckBox на свою функцию cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)

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

 QSignalMapper *m_sigmapper = new QSignalMapper(this);
 QObject::connect(pCheckBox, SIGNAL(mapped(QTableWidget*,int, QCheckBox*)), pCheckBox, SIGNAL(clicked()));
 QObject::connect(this, SIGNAL(clicked()), this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

 m_sigmapper->setMapping(pCheckBox, (monTab,ligne, pCheckBox));
 QObject::connect(m_sigmapper, SIGNAL(clicked()),this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

Можете ли вы объяснить мне, как работает QSignalMapper? Не очень понимаю, с чем ассоциировать :(


person Evans Belloeil    schedule 17.06.2014    source источник
comment
почему вы должны использовать QSignalMapper? какая-то конкретная причина? это можно легко сделать при прямом подключении   -  person Rakib    schedule 17.06.2014
comment
Ну, в другом посте мне объясняют, что сигнал не может быть подключен к слоту с большим количеством параметров, а сигнал clicked() не имеет параметров. Также мне нужны эти 3 параметра.   -  person Evans Belloeil    schedule 17.06.2014
comment
true, слот может иметь равное или меньшее количество параметров, чем соответствующий сигнал. но вы можете написать слот, который не принимает параметров, а затем вызвать из него фактический слот/метод с требуемым параметром.   -  person Rakib    schedule 17.06.2014
comment
Да, но как передать ему 3 параметра: QTableWidget *monTab, int ligne, QCheckBox *pCheckBox? Если вы прочитаете другой пост, у меня будет сотня qCheckBox, поэтому я не могу использовать указатели.   -  person Evans Belloeil    schedule 17.06.2014
comment
@EvansBelloeil Чтобы понять, как работает QSignalMapper, вот хороший пример для ты для начала.   -  person Tay2510    schedule 17.06.2014
comment
@ Tay2510 Я это уже читал, но спасибо, может я и тупой, но мне это не особо помогает.   -  person Evans Belloeil    schedule 17.06.2014
comment
@EvansBelloeil Я думаю, вам нужен QSignalMapper, потому что у вас есть много виджетов, которые излучают сигнал, и вы хотите знать в слоте назначения, какой из них излучает сигнал.   -  person Nejat    schedule 17.06.2014
comment
@Nejat Да, я тоже так думаю, но я не совсем понимаю, как вызвать функцию подключения, какова цель setMapping, ...   -  person Evans Belloeil    schedule 17.06.2014
comment
@EvansBelloeil Это лучший пример, который я когда-либо находил, и он подробно объясняет QSignalMapper шаг за шагом. Вам просто нужно размышлять об этом, и это требует времени. Я думаю, что вы слишком торопитесь с решением этой проблемы; это не имеет ничего общего с глупостью или нет.   -  person Tay2510    schedule 17.06.2014


Ответы (2)


QSignalMapper собирает набор сигналов без параметров и повторно передает их с целочисленными, строковыми или виджетными параметрами, соответствующими объекту, отправившему сигнал. Таким образом, вы можете иметь один как:

QSignalMapper * mapper = new QSignalMapper(this);
QObject::connect(mapper,SIGNAL(mapped(QWidget *)),this,SLOT(mySlot(QWidget *)));

Для каждой из ваших кнопок вы можете подключить сигнал clicked() к слоту map() QSignalMapper и добавить сопоставление с помощью setMapping, чтобы, когда clicked() подается сигнал от кнопки, излучался сигнал mapped(QWidget *):

QPushButton * but = new QPushButton(this);

QObject::connect(but, SIGNAL(clicked()),mapper,SLOT(map()));
mapper->setMapping(but, but);

Таким образом, всякий раз, когда вы нажимаете кнопку, испускается сигнал mapped(QWidget *) маппера, содержащий виджет в качестве параметра.

person Nejat    schedule 17.06.2014
comment
Спасибо ! Это работает, но как я могу поставить 3 параметра? Это возможно ? Потому что кажется, что я могу поставить только 1 из-за сопоставления (QWidget *) - person Evans Belloeil; 17.06.2014
comment
Невозможно иметь более одного параметра. Вы можете иметь другой виджет в качестве членов класса и получать к ним доступ в слоте. - person Nejat; 17.06.2014
comment
Что ты имеешь в виду, член класса? Если я не могу передать его как параметр, как я могу его найти? - person Evans Belloeil; 17.06.2014
comment
Я имею в виду, что вы можете поместить указатели на свои виджеты в файл класса .h как приватный. Затем вы можете получить к ним доступ. - person Nejat; 17.06.2014
comment
Нет. Глобальные переменные не должны использоваться в объектно-ориентированном программировании. Вы можете просто иметь доступ к указателю ваших виджетов в вашем классе. - person Nejat; 17.06.2014
comment
Давайте продолжим обсуждение в чате. - person Evans Belloeil; 17.06.2014

Сначала я объясню вам, как работает QSignalMapper. Тогда я объясню вам, почему вам это не нужно.

Как работает QSignalMapper:

Создайте QSignalMapper. Предположим, что вы хотите присвоить целочисленное значение каждому флажку, поэтому каждый раз, когда вы нажимаете на любой флажок, вы будете получать сигнал с назначенным ему целочисленным значением.

Подключите сигнал картографа к вашему SLOT, который вы будете реализовывать:

connect(mapper, SIGNAL(mapped(int)), this, SLOT(yourSlot(int)));

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

Пока вы создаете флажки, для каждого флажка вам нужно сделать следующее:

mapper->setMapping(checkBox, integerValueForThisCheckbox);
connect(checkBox, SIGNAL(clicked()), mapper, SLOT(map()));

С этого момента каждый раз, когда вы нажимаете на флажок, он будет посылать сигнал clicked() в QSignalMapper, который затем сопоставляет его с назначенным целочисленным значением и будет излучать сигнал mapped(). Вы подключились к этому сигналу mapped(), поэтому yourSlot(int) будет вызываться с правильным целочисленным значением.

Вместо целых чисел можно указать QString, QWidget* или QObject* (см. документацию Qt).

Вот как работает QSignalMapper.

Вам это не нужно:

  • QTableWidget *monTab — это единственный объект, он не меняется. Сохраните его как поле члена класса и используйте его из своей функции слота.
  • QCheckBox *pCheckBox — вы можете получить его, соединив sender() с QCheckBox*.

Так:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;
}

Функция sender() происходит от функции QObject, от которой вы наследуете, поэтому у вас есть к ней доступ.

  • int linge (это номер строки, верно?) - когда вы создаете флажки, вы можете хранить указатели на эти флажки в поле класса QList и использовать его из вашей функции слота, чтобы узнать, какая это строка, например:

В объявлении класса:

private:
    QList<QCheckBox*> checkboxes;

При создании флажков:

QCheckBox* cb = new QCheckBox();
checkboxes << cb;

В вашей функции слота:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;

    int linge = checkboxes.indexOf(pCheckBox);
}

Если вы хотите, вы можете пропустить этот QList и использовать QSignalMapper и назначать строки флажкам с помощью картографа. Это просто вопрос того, что вы предпочитаете.

person Googie    schedule 17.06.2014
comment
Спасибо за ваш ответ, который очень хороший и очень полный. Моя проблема в том, что есть несколько QTableWidget, поэтому, если я не использую QSignalMapper, мой способ доступа к этому QTableWidget - использовать parent() в QCheckBox, я думаю. Кажется, что я вынужден использовать много трюков, и это может вызвать проблемы, потому что мой код должен быть гибким. Поэтому я сначала попробую с QSignalMapper. Не могли бы вы предоставить мне более подробную информацию об этом? (извините, мне это очень трудно понять) - person Evans Belloeil; 17.06.2014