对事件循环中槽的调用排队,由Qt按向后顺序处理



在我正在处理的应用程序中,我有一个QLineEdit,它附加了一个标准的QObject::连接到插槽:

QObject::connect(m_searchBar, SIGNAL(textChanged(const QString &)),this,SLOT(slot_searchBar()));

如您所见,它正在将文本更改信号连接到我创作的插槽。此插槽如下所示:

   void LibraryWidget::slot_searchBar() 
{
    QString stringToFind = m_searchBar->text();
    m_searchResults->clear();
    if(stringToFind.isEmpty())
    {
        //set stacked widget back to the library when no text in search bar 
        m_libraryAndSearch->setCurrentWidget(libTree);
    } 
    else 
    {
        //show the search results
        QFont headerFont;
        QTreeWidgetItem * searchingMsg = new QTreeWidgetItem;
        headerFont = searchingMsg->font(0);
        headerFont.setBold(false);
        headerFont.setItalic(true);
        searchingMsg->setText(0, "Searching...");
        searchingMsg->setFont(0, headerFont);
        Qt::ItemFlags currentState = searchingMsg->flags();
        Qt::ItemFlags noSelect = (!(Qt::ItemIsSelectable) & currentState);
        searchingMsg->setFlags(noSelect);
        m_searchResults->addTopLevelItem(searchingMsg);
        m_libraryAndSearch->setCurrentWidget(m_searchResults);
        //m_searchThread->setTerminateAndWait();    
        //m_searchThread->beginThread(stringToFind);
        int testTwo = 0;
        for(int testInt = 0; testInt < 1000000000; testInt++)
        {
            testTwo++;
        }
        int testingThree = 0;
    }
}

希望这的重要性有限,但最好向您展示以防问题的根源出在这里。

如果我在搜索栏中输入一个字符串,即有问题的QLineEdit(很快),并查看附加的调试器(Visual Studio 2010)发生了什么,那么我会看到最奇怪的事情:

如果我的搜索

栏中已经有"Jake"(来自之前的搜索,输入缓慢),然后快速键入"gh",那么stringToFind值在第一次通过插槽时是"Jakegh",然后在第二次运行时是"Jakeg"。

就好像Qt将信号发射添加到堆栈而不是队列中,然后以相反的顺序将它们服务回事件循环。

问题是:有人知道这里发生了什么吗?有没有人经历过类似的结果?

Qt 版本 4.7

代码只是

为了重现问题,它不做任何事情。 int testTwo -> int testingThree 只是为了减慢代码速度。

谢谢。。。

编辑当字符串作为函数参数传入槽时,观察到相同的行为。该行

QString stringToFind = m_searchBar->text();

是试图调试和规避这种现象。

编辑二

我试图在家里重现这个。在Mac OS X 10.7上从终端构建Qt,因此没有可用的调试器。我正在使用一个非常简单的类和main.cpp其格式与上述格式相同,我无法使Qt以相反的顺序为我提供字母。不过,我可以让它错过信号。我已经将行编辑连接到文本编辑,以便每次行编辑中的文本更改时,它都会使用 QTextEdit::append(( const QString & text )) 打印到文本编辑中。

例如,如果我输入"N","

e","w",则应将"N","Ne","New"打印到文本编辑中。但是,有时它只是打印"N","新"。我有一个 for 循环,可以减慢一切速度,并且必须非常快速地按下按键。

导致这种现象第一次发生的系统必然比我构建的系统复杂得多,它在调试中运行并且运行缓慢。仍然不明白为什么这会导致这种行为,而且绝对是这样!

不要抓取文本,使用 QString 和信号。

QObject::connect(m_searchBar, SIGNAL(textChanged(const QString &)),this,SLOT(slot_searchBar(const QString &))); 

然后后来

void LibraryWidget::slot_searchBar(const QString &stringToFind) {
...

至于你看到你的行为的原因,我几乎可以肯定它是Qt::QueuedConnection在某个时候。您也可以在单线程代码中使用 QueuedConnection,它只需等到下一个事件循环来执行其中的代码。查看它的详细信息:http://qt-project.org/doc/qt-4.8/qt.html#ConnectionType-enum。

明显的问题是你的延迟循环,据说模拟实际搜索的作用。这正是错误的处理方式。搜索应在单独的 QObject 中异步运行,然后可以移动到单独的线程。只需将搜索栏中的信号连接到搜索器对象,然后当搜索者有新结果时,它应该会发出信号。

您的测试延迟循环应该替换为类似 QTimer::singleShot(1000, this, SLOT(fakeResults())) 的东西,其中插槽中的代码调用 GUI 中的相关插槽,并带有一些虚假结果。

我建议你也把一个"观察者"对象附加到QLineEdit,以监控事物。方法如下:

// in some file, say foo.cpp
class Watcher : public QObject
{
  Q_OBJECT
  QPointer<QLineEdit*> const edit;
public:
  Watcher(QLineEdit * ed, QObject * parent = 0) : QObject(parent), edit(ed) {
    connect(ed, SIGNAL(textChanged(QString)), SLOT(monitor(QString)));
  }
public slots:
  void monitor(const QString & str) {
    qDebug("Line edit signals text: %s", str.toLocal8Bit().constData());
    if (! edit.isNull() && edit->text() != str) {
      qDebug("... but line edit has text %s", edit->text().toLocal8Bit().constData());
    }
  }
}
#include "foo.moc" // replace 'foo' with actual name of the file (sans .cpp)

最新更新