【问题标题】:QLineEdit editingFinished signal twice when changing focus?QLineEdit editingFinished 信号在改变焦点时两次?
【发布时间】:2015-01-03 02:54:44
【问题描述】:

我发现了一些类似的问题,但这些似乎是指在插槽处理程序中使用消息框的情况。就我而言,我有点卡住了,因为即使我的插槽处理程序什么都不做,我也收到了两次 editFinished 信号。

对于测试,我有一个 QLineEdit 数组,它使用 signalMapper 将 editingFinished() 信号连接到单个插槽。 signalMapper 传递数组索引,因此我可以看到信号的来源。 例如:

testenter::testenter(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::testenter)
{
    // setup the UI according to the .h file
    ui->setupUi(this);

    signalMapper = new QSignalMapper(this);

    // init the labels and edit boxes
    for (int i = 0; i < 10; i++)
    {
        pm_label[i] = new QLabel(ui->scrollArea);
        QString text = QString("Number %1").arg(i);
        pm_label[i]->setText(text);
        pm_label[i]->setGeometry(10,20+i*30, 50, 20);
        pm_label[i]->show();

        pm_editBox[i] = new QLineEdit(ui->scrollArea);
        pm_editBox[i]->setGeometry(80,20+i*30, 50, 20);
        pm_editBox[i]->show();

        signalMapper->setMapping(pm_editBox[i], int(i));
        connect(pm_editBox[i], SIGNAL(editingFinished()), signalMapper, SLOT(map()));
    }
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(data_entry(int)));
}

void testenter::data_entry(int entry)
{
    //dummy
}

当在调试器中运行时,如果我在一个框中输入数据然后点击返回或用鼠标选择另一个框(即更改焦点),然后它调用 data_entry 两次,第一次使用丢失的框的索引焦点和第二次获得焦点的框。

所以我的问题是:我错过了什么吗?这是预期的行为还是错误? 如果是错误,任何人都知道解决方法,因为我想在输入数据时使用此信号对数据进行自定义验证(通过返回、制表符或鼠标单击来更改焦点)。

【问题讨论】:

  • Toby,Qt 的信号槽机制可以成为一个有趣的野兽。您遇到这种行为的条件是什么? (即在带有断点的调试器中,在没有调试的情况下运行并且结果出现两次)

标签: c++ qt qlineedit qt-signals qt-slot


【解决方案1】:

首先,这不是预期的行为,即选择 QLineEdit 不应导致它的 editingFinished 信号被发射。

有几个可能的原因可能会导致此问题:

  • 您不小心将信号两次连接到插槽
  • 插槽map() 导致新选择的框失去焦点
  • 同样徒劳,如果您正在调试并使用断点来检测插槽何时被调用,则当活动应用程序从您的 QWidget 更改为您的调试器时,您可能会导致 QLineEdit 失去焦点,再次导致信号再次发送。

如果您因为双连接插槽而遇到问题,但似乎并非如此,因为您专门从两个不同的QLineEdits 获取信号,您可以确保这不是通过指定连接类型发生,connect 方法实际上在末尾有一个额外的可选参数,允许您将类型从 DefaultConnection 更改为 UniqueConnection

话虽如此,数据验证是 Qt 已建立的机制,我建议您尽可能使用它,并考虑扩展 QValidator 抽象基类 Ref Doc。然后你告诉你的每个QLineEdit 使用相同的validator

【讨论】:

  • 我又玩了一场,看来你的第三个选项是问题所在。 IE。调试器导致焦点更改。 qDebug()
【解决方案2】:

我遇到了同样的问题。它确实会发出两次信号,这是一个已知的错误:https://bugreports.qt.io/browse/QTBUG-40,但是很长一段时间都没有解决。

最后我发现在我的情况下最好的解决方案是将信号从editingFinished 更改为returnPressed。作为副作用,从用户的角度来看,这表现得更加可预测。也可以在这里查看:http://www.qtforum.org/article/33631/qlineedit-the-signal-editingfinished-is-emitted-twice.html?s=35f85b5f8ea45c828c73b2619f5750ba9c686190#post109943

【讨论】:

  • 它已在 5.14 alpha 中得到修复...一个存在 14 年之久的错误,曾经因为人们没有投票而被忽略...
【解决方案3】:

OP“发现了一些类似的问题,但这些似乎是指在插槽处理程序中使用消息框的情况。”好吧,这也是我的情况,这就是我结束的地方。所以,冒着跑题的风险……

在我的情况下,当我的插槽接收到从QLineEdit 发送的editingFinished 信号时,我会启动一个模态QMessageBox 来询问用户一些事情。该消息框的出现触发了QLineEdit 发送第二个不受欢迎的editingFinished 信号。

@V.K. 提到的错误报告 (https://bugreports.qt.io/browse/QTBUG-40) 中的一个帖子。提供了一个对我有帮助的解决方法。以下是我对解决方法的实现。我让 Qt magic mojo 自动将QLineEdit 信号连接到我的MainWindow 插槽。

void MainWindow::on_textbox_editingFinished( void )
{
  QLineEdit * pTextbox = qobject_cast<QLineEdit *>( QObject::sender() );
  if ( !pTextbox->isModified() )
  {
    // Ignore undesirable signals.
    return;
  }

  pTextbox->setModified( false );

  // Do something with the text.
  doSomething( pTextbox->text() );
}

void MainWindow::doSomething( QString const & text )
{
  QMessageBox box( this );
  box.setStandardButtons( QMessageBox::Yes | QMessageBox::No );
  box.setText( "Are you sure you want to change that text value?" );
  if ( box.exec() == QMessageBox::Yes )
  {
    // Store the text.
    m_text = text;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 2011-10-04
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 2020-02-07
    • 2010-10-06
    相关资源
    最近更新 更多