如何通过同一个按钮调用不同的插槽?

时间:2015-10-16 14:11:15

标签: qt signals call signals-slots slots

两天以来,我一直试图理解为什么我的应用程序上的同一个按钮调用了不同的插槽。我已经搜索了很多关于这个主题的信息,但主要是I found关于通过同一个按钮多次调用一个唯一SLOT的问题,该问题在连接调用时添加了第五个参数Qt::UniqueConnection 即:

  

connect(obj,SIGNAL(signal()),obj2,SLOT(slot()),   Qt的:: UniqueConnection);

继续前进,我的问题是同一个按钮在它不应该调用时调用不同的插槽。我创建了一个通用代码来设置我的所有按钮:

void KHUB::btSetupInt(QPushButton **button, const QString name, int posX, int posY, int width, int height, void (KHUB::*fptr)(int parameter), int value, int handler) {
  *button = new QPushButton(name, this);
  (*button)->setGeometry(QRect(QPoint(posX, posY), QSize(width, height)));

  signalMapper->setMapping(*button, value);
  connect(*button, SIGNAL(clicked()), signalMapper, SLOT(map()));
  //qDebug() << "My value: " + QString::number(value);

  switch (handler) {
    case (int) ButtonHandler::hl_Register:
      connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleRegister(int)), Qt::UniqueConnection);
      break;
    case (int)ButtonHandler::hl_UpVote:
      connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleUpVote(int)), Qt::UniqueConnection);
      break;
    case (int) ButtonHandler::hl_OpenUrl:
      //connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleUrl(int)), Qt::UniqueConnection);
      break;
    case (int)ButtonHandler::hl_DownVote:
      connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleDownVote(int)), Qt::UniqueConnection);
      break;
    case (int) ButtonHandler::hl_DisposeBrowser:
      connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleDispose(int)), Qt::UniqueConnection);
      break;
    }
}

在其中,我的signalMapper在我的头文件中声明。此按钮设置由以下方式调用:

void KHUB::handleSearch() {
  //DO THE MATH
  for (int pos = 0; pos < localUrl.size(); pos++){
    QLabel *link = new QLabel();
    link->setText("<a href=\"" + localUrl.at(pos) + "\">" + localUrl.at(pos) + "</a>");
    link->setTextFormat(Qt::RichText);
    link->setTextInteractionFlags(Qt::TextBrowserInteraction);
    link->setOpenExternalLinks(true);

    QPushButton *upArrow = new QPushButton();
    btSetupInt(&upArrow, "Up Vote", 225, 300, 100, 25, &KHUB::handleUpVote, pos*147, (int)ButtonHandler::hl_UpVote);

    QPushButton *open = new QPushButton("Open");
    //btSetupInt(&open, "Open", 225, 300, 100, 25, &KHUB::handleUrl, pos, (int) ButtonHandler::hl_OpenUrl);

    QPushButton *downArrow = new QPushButton();
    btSetupInt(&downArrow, "Down Vote", 225, 300, 100, 25, &KHUB::handleDownVote, pos*163, (int)ButtonHandler::hl_DownVote);

    QLabel *separator = new QLabel();
    QLabel *guider = new QLabel("<----------------------------------------------------------------------------------------------------------------------------------------------------->");

    gridLayout->addWidget(link, componentsPos, 0, 1, -1);
    gridLayout->addWidget(guider, componentsPos, 1, 1, -1);
    gridLayout->addWidget(upArrow, componentsPos - 1, 2, 1, 1, Qt::AlignBottom);
    gridLayout->addWidget(open, componentsPos, 2, 1, 1);
    gridLayout->addWidget(downArrow, componentsPos + 1, 2, 1, 1, Qt::AlignTop);
    gridLayout->addWidget(separator, componentsPos + 2, 1, 1, 1);

    componentsPos = componentsPos + 5;
  }
  //KEEP DOING THE MATH
}

注释行与调试目的一样。无论如何,当我只有open QPushButton时,这段代码完全正常工作。添加upVotedownVote后,我希望程序能够复制其逻辑成功,相反,现在当我点击进行投票时,ou Down投票程序会触发两个槽来处理Up和Down votin以及&# 34;开&#34;如果没有评论。处理上下投票的代码:

void KHUB::handleUpVote(int reference) {
    qDebug() << "This is my reference for upvoting: " + QString::number(reference/147);
}

void KHUB::handleDownVote(int reference) { 
    qDebug() << "This is my reference for DOWNVOTING: " + QString::number(reference/163);
}

根据Qt QSignalMapper documentation(主题&#34;高级信号和广告位使用情况&#34;在页面结束时)我按预期执行所有操作。你也必须注意到我成倍增加 posbtSetupInt拨打147和163(以生成&#34;随机&#34;号码)every button must have its only integer ID以后的void QSignalMapper::setMapping(QObject * sender, int id) [请参阅setMapping for integers pos]。

几天前,我对其中三个(按钮)使用了相同的位置("This is my reference for upvoting: 3" "This is my reference for DOWNVOTING: 3" ),以及产生的结果是否相等。 这引出了我的第一个问题: 此ID是每个按钮的唯一标识符,还是按钮可以传递的唯一参数?我仍然没有考虑到我上面给出的背景,得到这个

这是我的用户界面:

Application UI

这是我的输出点击(随机链接选择)向上投票us.battle.net/wow/en/blog/19913791/patch-623-preview-10-14-2015

"This is my reference for upvoting: 6"
"This is my reference for DOWNVOTING: 6"

这是我的输出点击(随机链接选择)向下投票http://www.swtor.com/holonet/companions/blizz

handler

我使用了断点来查看btSetupInt处的btSetupInt切换是否被正确调用了。即使不使用我的成员函数class Parent { } class Child: Parent { } 来调用连接,我仍然会得到相同的错误结果。 完成,我的第二个主要问题在给定的上下文中,如果同一个按钮调用不同的插槽,怎么可能?我在这里缺少什么?

2 个答案:

答案 0 :(得分:1)

因为您连接信号映射器多次,即每个按钮实例。您正在创建一个按钮,然后根据您连接到另一个插槽的handler。但信号映射器的mapped(int)信号连接到多个插槽。希望你能得到我在这里所说的话。

您的代码的另一个问题是内存泄漏。

QPushButton *upArrow = new QPushButton();
btSetupInt(&upArrow, "Up Vote", 225, 300, 100, 25, &KHUB::handleUpVote, pos*147, (int)ButtonHandler::hl_UpVote);

btSetupInt()正在创建新按钮。试。

*button = new QPushButton(name, this);

这是未经测试的代码。检查它是否有效。

// custom button claas
class VotingButton : public QPushButton
{
    Q_OBJECT

public:
    VotingButton(const QString& url, int voteType, QObject* prnt=0)
        : QPushButton(prnt)
          m_url(url),
          m_voteType(voteType)
    {}

    QString getUrl() const { return m_url; }
    int getVoteType() const { return m_voteType; } 

private:
    QString     m_url;
    int         m_voteType;
}

在您的KHUB班级

connect(signalMapper, SIGNAL(mapped(QObject*)), this, SLOT(handleButtonPress(QObject*)));

void KHUB::btSetupInt(QPushButton* button, const QString& name, int posX, int posY, int width, int height, const QString& url, int handler) {
    button = new VotingButton(url, handler, this);
    button->setText(name);
    button->setGeometry(QRect(QPoint(posX, posY), QSize(width, height)));
    signalMapper->setMapping(button, this);
    connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
}

void KHUB::handleSearch() {
  //DO THE MATH
  for (int pos = 0; pos < localUrl.size(); pos++){
    QLabel *link = new QLabel();
    link->setText("<a href=\"" + localUrl.at(pos) + "\">" + localUrl.at(pos) + "</a>");
    link->setTextFormat(Qt::RichText);
    link->setTextInteractionFlags(Qt::TextBrowserInteraction);
    link->setOpenExternalLinks(true);

    QPushButton *upArrow;
    btSetupInt(upArrow, "Up Vote", 225, 300, 100, 25, localUrl.at(i), (int)ButtonHandler::hl_UpVote);

    QPushButton *open;
    btSetupInt(open, "Open", 225, 300, 100, 25, localUrl.at(i), (int)ButtonHandler::hl_OpenUrl);    

    QPushButton *downArrow;
    btSetupInt(downArrow, "Down Vote", 225, 300, 100, 25, localUrl.at(i), (int)ButtonHandler::hl_DownVote);

    QLabel *separator = new QLabel();
    QLabel *guider = new QLabel("<----------------------------------------------------------------------------------------------------------------------------------------------------->");

    gridLayout->addWidget(link, componentsPos, 0, 1, -1);
    gridLayout->addWidget(guider, componentsPos, 1, 1, -1);
    gridLayout->addWidget(upArrow, componentsPos - 1, 2, 1, 1, Qt::AlignBottom);
    gridLayout->addWidget(open, componentsPos, 2, 1, 1);
    gridLayout->addWidget(downArrow, componentsPos + 1, 2, 1, 1, Qt::AlignTop);
    gridLayout->addWidget(separator, componentsPos + 2, 1, 1, 1);

    componentsPos = componentsPos + 5;
  }
  //KEEP DOING THE MATH
}

void KHUB::handleButtonPress(QObject* obj)
{
    VotingButton* voteButton = static_cast<VotingButton*>(obj);
    if (voteButton) { // now you have voteType and the url assigned to the button
        switch (voteButton->getVoteType())
        {
            case ...
        }
    }
}

答案 1 :(得分:0)

据我所知,基于ramtheconqueror的答案,你不能使用相同的地图来连接不同的插槽。在我的代码中,我使用signalMapper连接到不同的处理程序(插槽),为了解决这个问题,我在btSetupInt添加了一个QSignalMapper参数。我为每个按钮类型创建了三个不同的地图,以提供我想要连接插槽的地图。

我的代码现在看起来像这样:

void KHUB::btSetupInt(QPushButton **button, const QString name, int posX, int posY, int width, int height, void (KHUB::*fptr)(int parameter), QSignalMapper* map, int value, int handler) {
  *button = new QPushButton(name, this);
  (*button)->setGeometry(QRect(QPoint(posX, posY), QSize(width, height)));

  map->setMapping(*button, value);
  connect(*button, SIGNAL(clicked()), map, SLOT(map()));
  //qDebug() << "My value: " + QString::number(value);

  switch (handler) {
    case (int) ButtonHandler::hl_Register:
      connect(map, SIGNAL(mapped(int)), this, SLOT(handleRegister(int)), Qt::UniqueConnection);
      break;
    case (int)ButtonHandler::hl_UpVote:
      connect(map, SIGNAL(mapped(int)), this, SLOT(handleUpVote(int)), Qt::UniqueConnection);
      break;
    case (int) ButtonHandler::hl_OpenUrl:
      //connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handleUrl(int)), Qt::UniqueConnection);
      break;
    case (int)ButtonHandler::hl_DownVote:
      connect(map, SIGNAL(mapped(int)), this, SLOT(handleDownVote(int)), Qt::UniqueConnection);
      break;
    case (int) ButtonHandler::hl_DisposeBrowser:
      connect(map, SIGNAL(mapped(int)), this, SLOT(handleDispose(int)), Qt::UniqueConnection);
      break;
    }
}

  void KHUB::handleSearch() {
  //DO THE MATH
  upVoteMap = new QSignalMapper(this);
  downVoteMap = new QSignalMapper(this);
  openMap = new QSignalMapper(this);

   for (int pos = 0; pos < localUrl.size(); pos++){
    QLabel *link = new QLabel();
    link->setText("<a href=\"" + localUrl.at(pos) + "\">" + localUrl.at(pos) + "</a>");
    link->setTextFormat(Qt::RichText);
    link->setTextInteractionFlags(Qt::TextBrowserInteraction);
    link->setOpenExternalLinks(true);

    QPushButton *upArrow;
    btSetupInt(&upArrow, "Up Vote", 225, 300, 100, 25, &KHUB::handleUpVote, upVoteMap, pos, (int)ButtonHandler::hl_UpVote);

    QPushButton *open;
    btSetupInt(&open, "Open", 225, 300, 100, 25, &KHUB::handleUrl, openMap, pos, (int) ButtonHandler::hl_OpenUrl);

    QPushButton *downArrow;
    btSetupInt(&downArrow, "Down Vote", 225, 300, 100, 25, &KHUB::handleDownVote, downVoteMap, pos, (int)ButtonHandler::hl_DownVote);

    QLabel *separator = new QLabel();
    QLabel *guider = new QLabel("<----------------------------------------------------------------------------------------------------------------------------------------------------->");

    gridLayout->addWidget(link, componentsPos, 0, 1, -1);
    gridLayout->addWidget(guider, componentsPos, 1, 1, -1);
    gridLayout->addWidget(upArrow, componentsPos - 1, 2, 1, 1, Qt::AlignBottom);
    gridLayout->addWidget(open, componentsPos, 2, 1, 1);
    gridLayout->addWidget(downArrow, componentsPos + 1, 2, 1, 1, Qt::AlignTop);
    gridLayout->addWidget(separator, componentsPos + 2, 1, 1, 1);

    componentsPos = componentsPos + 5;
  }
  //KEEP DOING THE MATH
}

我相信ramtheconqueror的解决方案可行,并且肯定它比我的更好,虽然它不适用于我的情况,因为我正在研究论文并证明我的POV我需要创建有限数量的类预先建立的。

无论如何,我会认为他的答案是正确的,因为没有他我就不会意识到自己的答案。

不幸的是,我仍然没有第一个问题的答案,但我希望一般来说这有助于将来。

干杯