问题 如何在QT中将变量传递给slot方法?


我正在制作一个聊天信使程序,需要用户加入的聊天频道列表。为了以图形方式表示此列表,我列出了一个列表 QPushButtons,这些都代表着不同的渠道。这些按钮是使用以下方法制作的,这就是我的问题所在:

void Messenger::addToActivePanels(std::string& channel)
{
    activePanelsContents = this->findChild<QWidget *>(QString("activePanelsContents"));
    pushButton = new QPushButton(activePanelsContents);
    pushButton->setObjectName("pushButton");
    pushButton->setGeometry(QRect(0, 0, 60, 60));
    pushButton->setText("");
    pushButton->setToolTip(QString(channel.c_str()));
    pushButton->setCheckable(true);
    pushButton->setChecked(false);
    connect(pushButton, SIGNAL(clicked()), this, SLOT(switchTab(channel)));
}

(activePanelContents是一个保存列表的QWidget。)

关键是每个按钮都应该调用 switchTab(string& tabname) 单击时的方法,包括特定通道的名称作为变量。这个实现虽然不起作用,但我还是找不到如何正确地做到这一点。


1114
2018-02-07 23:20


起源



答案:


对于字符串和整数,您可以使用QSignalMapper。在你的 Messenger 上课,你会添加一个 QSignalMapper mapper 对象,你的函数看起来像:

void Messenger::addToActivePanels(std::string& channel)
{
    activePanelsContents = this->findChild<QWidget *>(QString("activePanelsContents"));
    pushButton = new QPushButton(activePanelsContents);
    // ...
    connect(pushButton, SIGNAL(clicked()), &mapper, SLOT(map()));
    mapper.setMapping(pushButton, QString(channel.c_str()));
}

将所有频道添加到活动面板后,即可致电

connect(&mapper, SIGNAL(mapped(const QString &)), this, SLOT(switchTab(const QString &)));

7
2018-02-08 03:11



这似乎不起作用...尽管根本没有给出任何错误,但switchTab()根本就不会被调用。 - Neko
是否 switchTab() 拿一个 const QString &?如果没有,您需要更改它。 Qt不允许你通过 std::string (或者,一般来说,任何未注册的类型 qRegisterMetaType)通过信号和插槽。错别字里面 SIGNAL 和 SLOT 直到运行时才检测到,因为这些宏将其参数转换为字符串。有可能Qt在尝试建立连接时向控制台打印错误消息 switchTab(const QString &)。 - Daniel Gallagher


答案:


对于字符串和整数,您可以使用QSignalMapper。在你的 Messenger 上课,你会添加一个 QSignalMapper mapper 对象,你的函数看起来像:

void Messenger::addToActivePanels(std::string& channel)
{
    activePanelsContents = this->findChild<QWidget *>(QString("activePanelsContents"));
    pushButton = new QPushButton(activePanelsContents);
    // ...
    connect(pushButton, SIGNAL(clicked()), &mapper, SLOT(map()));
    mapper.setMapping(pushButton, QString(channel.c_str()));
}

将所有频道添加到活动面板后,即可致电

connect(&mapper, SIGNAL(mapped(const QString &)), this, SLOT(switchTab(const QString &)));

7
2018-02-08 03:11



这似乎不起作用...尽管根本没有给出任何错误,但switchTab()根本就不会被调用。 - Neko
是否 switchTab() 拿一个 const QString &?如果没有,您需要更改它。 Qt不允许你通过 std::string (或者,一般来说,任何未注册的类型 qRegisterMetaType)通过信号和插槽。错别字里面 SIGNAL 和 SLOT 直到运行时才检测到,因为这些宏将其参数转换为字符串。有可能Qt在尝试建立连接时向控制台打印错误消息 switchTab(const QString &)。 - Daniel Gallagher


使用 QSignalMapper 传递变量;

        QSignalMapper* signalMapper = new QSignalMapper (this) ;
        QPushButton *button = new QPushButton();


         signalMapper -> setMapping (button, <data>) ;
         connect (signalMapper, SIGNAL(mapped(QString)), this,   
                   SLOT(buttonClicked(QString))) ;

在插槽中

void class::buttonClicked(QString data){

    //use data
    // to get sender 
    QSignalMapper *temp = (QSignalMapper *)this->sender();
    QPushButton *btn = (QPushButton *)temp->mapping(data);
    // use btn

}

希望我的ans可以帮助你


3
2017-10-16 11:21



谢谢你的回答。我正在使用QSignalMapper和QTNetworkRequest,并且不知道在这种情况下我必须使用Mapper-> mapping(data)来获取对象。我只是使用qobject_cast <QObject *>(发送者),只有在没有参数时才有效。 - fayyazkl


除非绝对必须,否则请勿使用发送方法。它将函数直接绑定到仅用作插槽(不能直接调用)。保留让函数接受字符串的行为,并简单地创建一个可以调用它的机制。

您可能会发现,其中一种方法是利用QSignalMapper。它会将对象映射到值并重新生成相应签名的信号。


1
2018-02-08 00:39





我会用“relay”对象来做:

创建 TabSwitchRelay 这是一个子类 QObject 使用此构造函数:

TabSwitchRelay::TabSwitchRelay(QObject *parent, Messanger * m, const QString & c)
: QObject(parent), m_messanger(m), m_channel(c)
{
}

它还有一个插槽 clicked()

void TabSwitchRelay::clicked()
{
    m_messager->switchTab(m_channel);
}

现在替换代码中与此连接的行:

TabSwitchRelay * tabRelay = new TabSwitchRelay(pushButton, this, channel);
connect(pushButton, SIGNAL(clicked()), tabRelay, SLOT(clicked()));

它没有经过测试,但你得到了基本的想法。


1
2018-02-08 02:18





你可以试试你的 switchTab 插槽没有参数和使用 QObject::sender 获取发送信号的对象。

Messenger::switchTab()
{
  QObject* sender = this->sender();
  QPushButton* button = qobject_cast<QPushButton*>(sender);
  if(button)
  {
    // Do stuff...
  }
}

0
2018-02-07 23:42



在代码中使用QObject :: sender之前,请注意警告 - Patrice Bernassola
不确定为什么你的帖子被滥用,但无论如何,谢谢。你帮了很多忙 - parsecer


如果你使用的是Qt5,你可以通过lambda来实现:

connect( sender, &Sender::valueChanged,  [=](){ myMethod(5); } );

void myMethod(int value)
{
  // do stuff
}

0
2017-10-24 12:34