【问题标题】:QT signal slot not workingQT 信号槽不工作
【发布时间】:2015-07-31 20:31:11
【问题描述】:

为什么这段代码没有调用所需的槽?

我试图让它在过去 3 小时内正常工作!

void TForm::on_clicked( bool checked )
{
    QMessageBox *messageBox = new QMessageBox(this);
    QPushButton *buttonAccept0 = new QPushButton("OK", messageBox);
    QPushButton *buttonReject = new QPushButton("Cancel", messageBox);
    messageBox->addButton(buttonAccept0, QMessageBox::ButtonRole::AcceptRole);
    messageBox->addButton(buttonReject, QMessageBox::ButtonRole::NoRole);
    messageBox->setWindowTitle("Confirmation");
    messageBox->setText("Remove?");
    messageBox->setModal(true);
    messageBox->show(); 
    QObject::connect(buttonAccept0, SIGNAL(accepted()), this, SLOT(a1()));
}
void TForm::a1()
{
    std::string ff = "";
}

【问题讨论】:

  • QPushButton 没有名为 accepted() 的信号。在运行您的应用程序时,您应该已经看到了关于此的警告消息。

标签: qt signals-slots qt4.7


【解决方案1】:

您的问题有三点值得注意:


首先,您的错误是由于您使用了不正确的信号(正如其他成员已经提到的那样)。

要更正您的错误,请对您的代码进行以下更改:

QObject::connect(buttonAccept0, SIGNAL(clicked()), this, SLOT(at()));

其次,与他/她的回答中提到的@M74 不同,完全允许在on_clicked 函数内声明消息框和信号。 @M74 担心的原因是因为潜在的内存泄漏,但 Qt 有一种机制可以以父母的形式克服这一点,当您在函数开头定义消息框时,您正确地做到了这一点。

不幸的是,@M74 的担忧并非完全没有根据,因为消息框只会在父级被销毁时才会被销毁。

如果您的TForm 实例在整个应用程序期间都保持活动状态,并且您多次执行on_clicked,您将创建许多messageBox 实例并在后台等待被删除,这是一种内存泄漏本身。

避免这种情况的更好方法是修改代码以使messageBox 成为函数本地的堆栈变量。这两个QPushButton 实例仍然可以在堆内存中创建,因为它们会在消息框被销毁时自动销毁,这也是由于父级关系。

void TForm::on_clicked(bool checked)
{
    QMessageBox messageBox;
    QPushButton *buttonAccept0 = new QPushButton("Ok", &messageBox);
    QPushButton *buttonReject = new QPushButton("Cancel", &messageBox);
    messageBox.addButton(buttonAccept0, QMessageBox::AcceptRole);
    messageBox.addButton(buttonReject, MessageBox::NoRole);
    messageBox.setWindowTitle("Confirmation");
    messageBox.setText("Remove?");
    messageBox.setModal(true);
    connect(buttonAccept0, SIGNAL(clicked()), this, SLOT(a1()));
    messageBox.show();
}

注意:

  1. 通常最好在显示对话框之前设置所有连接,以防在建立连接之前触发信号。这就是我将show 语句移到最后的原因。

  2. 你可以替换这两个语句:

    messageBox.setModal(true);

    messageBox.show();

    messageBox.exec();

结果是一样的。


最后,

QMessageBox 带有许多用于通用目的的静态函数。问题中显示的代码完全适合标准用例之一,因此可以使用以下代码重写所有内容:

if (QMessageBox::question(nullptr, "Confirmation", "Remove?", 
    QMessageBox::Ok | QMessageBox::Cancel, 
    QMessageBox::Cancel) == QMessageBox::Ok)
{
    a1();
}

【讨论】:

  • 嗨@RobbieE,很好的答案,真的。谢谢你的帮忙。它工作得很好。关于您的最终评论,我不使用静态函数的原因是因为当我不在主线程中调用 exec() 时,它们会以某种方式使应用程序崩溃。我之前已经问过一个问题(stackoverflow.com/questions/31548664/qt-exec-command-crash)。如果您有其他选择,请与我分享! :-)
  • 不允许在辅助线程中使用 GUI 类,只能在主线程中使用。
  • exec()show() 是等价的说法是非常具有误导性的。 exec() 不属于质量代码,除了在一个还没有事件循环的线程中启动一个事件循环,以及为QDrag 混蛋。否则,它会导致伪同步意大利面条。请不要鼓励任何人将show() 替换为exec()
  • @KubaOber 我在很大程度上同意,但我认为他的意思是它们在功能上 是等效的。它们都阻塞了 GUI 线程并显示。
  • @ArnabDatta 不,不会。窗口模式和阻塞是两个不同的东西。当您显示应用程序模式窗口时,您只是阻止其他顶级小部件(窗口)接收用户输入。他们仍然会收到所有其他事件,并且就像用户没有与他们互动一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多