我基本上有多个事件信号,我想连接到同一个插槽。我想知道的是如何将基于字符串的参数传递到同一个插槽,以便插槽知道这个信号来自哪个。一种替代方案是制作与信号一样多的插槽,然后以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);
有人可以告诉我上述代码中的错误是什么吗?
答案 0 :(得分:8)
您可以使用QSignalMapper。虽然QSignalMapper是你问题的答案,但我认为jon hanson的回答是你应该采取的方式。你可以通过这种方式获得更清晰的代码。
答案 1 :(得分:8)
四种方法。一个人不会吮吸。
QSignalMapper
。可以工作,但会造成混乱的代码。sender()
- 进行比较。可以处理动态发件人,但仍然有点难看。特别是当您使用少量信号和发件人类型以及动态生成发件人时,将发件人子类化是最干净的方式。这使您可以重载现有信号以包含所需的任何参数。
现在,连接信号和插槽正常工作:
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
//...
}
并且额外的代码在您永远不必再触摸的子类中是不可见的。
有关子类化QPushButton
以发出clicked(int)
信号的示例实现,请参阅http://doc.qt.digia.com/qq/qq10-signalmapper.html#thesubclassapproach。还讨论了所有四种方法 - 命名槽(“普通解决方案”),sender(),子类化和信号映射器。
警告:显然最适合少量的发件人类型。但通常情况就是如此。在这种情况下,这是值得的。
答案 2 :(得分:5)
使用单独的插槽效率低下?如果在槽处理程序中存在共性,则将其移动到函数中,例如,扩展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);
}
答案 3 :(得分:4)
您不能将常量传递给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。
答案 4 :(得分:0)
如果你真的不想使用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)));
答案 5 :(得分:0)
现在,您可以在连接时真正绑定值。 Qt5增加了对此的支持。
示例:
connect(sender, &Sender::valueChanged,
tr1::bind(receiver, &Receiver::updateValue, "senderValue", tr1::placeholder::_1));
请参阅more info。
注意:你当然可以使用std :: bind或boost :: bind代替tr1 :: bind。