【问题标题】:How different slots are being called by the same button?同一个按钮调用了多少不同的插槽?
【发布时间】:2016-01-15 07:57:43
【问题描述】:

两天来,我一直在试图理解为什么我的应用程序上的同一个按钮会调用不同的插槽。我已经用谷歌搜索了很多关于这个主题的内容,但主要是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 时,我希望程序能够复制其逻辑成功,相反,现在当我单击“向上投票”或“向下投票”时,程序会触发处理向上和向下投票的两个插槽,如果没有评论,还会触发“打开” .处理赞成票和反对票的代码:

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(页面结尾处的主题“高级信号和插槽使用”)我正在按预期做所有事情。你也一定注意到我成倍增加 pos btSetupIntevery button must have its only integer ID 起通过 147 和 163 调用(生成“随机”数字)[请参阅 setMapping 获取整数 void QSignalMapper::setMapping(QObject * sender, int id)]。

几天前,我对它们中的三个(按钮)使用相同的位置 (pos),无论相乘与否,产生的结果是否相等。 这引出了我的第一个问题: 这个 ID 是每个按钮的唯一标识符还是按钮可以传递的唯一参数?我还是没明白考虑到我上面给出的上下文

这是我的用户界面:

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

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

这是我在http://www.swtor.com/holonet/companions/blizz 上单击(选择随机链接)Down Vote 的输出:

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

我使用断点查看btSetupInt 处的handler 开关是否被正确调用,并且是正确的。即使不使用我的成员函数btSetupInt 来调用连接,我仍然会得到相同的错误结果。 最后,我的第二个也是主要问题在给定的上下文中,同一个按钮怎么可能调用不同的插槽?我在这里错过了什么?

【问题讨论】:

  • 在将信号连接到新插槽之前,您需要将其与前一个插槽断开。然后一切都会正常工作。
  • 请启发我,我明白你的意思,但完全没有这个想法——我该怎么做?快速谷歌研究会在我的切换结束时类似于button-&gt;disconnect(SIGNAL(signal))

标签: qt signals call signals-slots slots


【解决方案1】:

据我根据 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,我需要创建数量有限的类预先建立的。

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

很遗憾,我仍然没有第一个问题的答案,但总的来说,我希望这对将来的某人有所帮助。

【讨论】:

    【解决方案2】:

    因为,您要多次连接信号映射器,即针对每个按钮实例。您正在创建一个按钮,然后根据 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 ...
            }
        }
    }
    

    【讨论】:

    • 非常感谢您的回答,谢谢;但是我需要几个小时才能测试它,我明天要考试,所以我会尽快回来回答发生了什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多