首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Qt变得反应迟钝,发射信号太快

Qt变得反应迟钝,发射信号太快
EN

Stack Overflow用户
提问于 2014-12-02 08:30:34
回答 2查看 743关注 0票数 0

我有一个小型聊天客户端,它将所有历史记录存储在sqlite数据库中。当用户单击我的应用程序中的history选项卡时,我的应用程序获取所有相关历史记录,并将其显示在QWebView中。Im从下面的背景线程dbThread获取,然后发送信号以相应地更新QWebView

这很好,直到数据库增长。当数据库变得更大时,应用程序几乎会崩溃。GUI在几秒钟内没有响应,直到加载所有内容(4-6秒),这取决于database大小。

我尝试在信号上添加Qt::QueuedConnection,并且像上面提到的一样,我正在处理来自background thread的所有database查询。

我猜我发出的信号太快了。有什么办法解决这个问题吗?

信号

代码语言:javascript
复制
connect(dbtrad, SIGNAL(addAllHistoryMessage(QString, QString, QString, QString, QString)), this, SLOT(addAllHistoryMessage(QString, QString, QString, QString, QString)), Qt::QueuedConnection);
connect(dbtrad, SIGNAL(addAllHistoryMessageInner(QString, QString, QString, QString, QString)), this, SLOT(addAllHistoryMessageInner(QString, QString, QString, QString, QString)), Qt::QueuedConnection);

从sqlite数据库获取历史记录的代码:

代码语言:javascript
复制
// Loads all local history
void dbThread::loadAllHistory(QString agentID, QString agentName) {
    bool ret = false;
    bool retInner = false;
    QString retVal = "";

    QDateTime dateTime = dateTime.currentDateTime();
    QString dateTimeForTodayCheck = dateTime.toString("yyyy-MM-dd");

    if (db.isOpen()) {
        QSqlQuery query(db);
        QSqlQuery queryInner(db);

        ret = query.exec(QString("SELECT channelID, sender, time, message from chatHistory WHERE sender != 'ServerMessage' AND channelID NOT LIKE '%Agent%' GROUP BY channelID order by time DESC;"));

        if (ret) {

            while (query.next()) {    
                QString channelID = query.value(0).toString();
                QString sender = query.value(1).toString();
                QString time = query.value(2).toString();
                QString msg = query.value(3).toString();


                QString timeStr;
                QString fmt = "yyyy-MM-dd hh:mm:ss";
                QDateTime dt = QDateTime::fromString(time, fmt);
                QDateTime dtCompare = QDateTime::fromString(time, fmt);

                if(dateTimeForTodayCheck == dtCompare.toString("yyyy-MM-dd")) { // If today
                    timeStr = "Today " + dt.toString("hh:mm");
                } else {
                    timeStr = dt.toString("dd MMM yyyy");
                }

                if(sender == agentID) {
                    sender = agentName;
                }
                // Grab all the tags
                QString tempTagsForChannelID = getHistoryTagsString(channelID);

                emit addAllHistoryMessage(channelID, sender, timeStr, msg, tempTagsForChannelID);

                // Load sub-history
                retInner = queryInner.exec(QString("SELECT * from chatHistory WHERE sender != 'ServerMessage' AND channelID = '%1' and message != '%2' order by time DESC;").arg(channelID).arg(msg));

                if (retInner) {
                    while (queryInner.next()) {
                        QString channelIDInner = queryInner.value(0).toString();
                        QString senderInner = queryInner.value(1).toString();
                        QString timeInner = queryInner.value(4).toString();
                        QString msgInner = queryInner.value(2).toString();

                        QString timeStr2;
                        QString fmt = "yyyy-MM-dd hh:mm:ss";
                        QDateTime dt = QDateTime::fromString(timeInner, fmt);
                        QDateTime dtCompare = QDateTime::fromString(timeInner, fmt);

                        if(dateTimeForTodayCheck == dtCompare.toString("yyyy-MM-dd")) { // If today
                            timeStr2 = "Today " + dt.toString("hh:mm");
                        } else {
                            timeStr2 = dt.toString("dd MMM yyyy");
                        }

                        if(senderInner == agentID) {
                            senderInner = agentName;
                        }

                        emit addAllHistoryMessageInner(channelIDInner, senderInner, timeStr2, msgInner, tempTagsForChannelID);
                    }
                }
            }
        }
    }
}

我要更新的代码:

代码语言:javascript
复制
void MainWindow::addAllHistoryMessageInner(QString channelIDInner, QString senderInner, QString timeStr2, QString msgInner, QString tempTagsForChannelID) {
    ui->webViewHistory->page()->mainFrame()->evaluateJavaScript("$('#history tbody').append('<tr id=\"" + channelIDInner+ "\" class=\"hiddenRow\"><td>" + senderInner + "</td><td align=\"center\">" + timeStr2 + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + msgInner.remove(QRegExp("<[^>]*>")) + "</td><td align=\"center\">" + tempTagsForChannelID + "</td></tr>');undefined");
}

void MainWindow::addAllHistoryMessage(QString channelID, QString sender, QString timeStr, QString msg, QString tempTagsForChannelID) {
    ui->webViewHistory->page()->mainFrame()->evaluateJavaScript("$('#history tbody').append('<tr id=\"" + channelID + "\"><td>" + sender + "</td><td align=\"center\">" + timeStr + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + msg.remove(QRegExp("<[^>]*>")) + "</td><td align=\"center\" style=\"word-wrap:break-word;\">" + tempTagsForChannelID + "</td></tr>');undefined");
}

编辑: dbThread的实现

代码语言:javascript
复制
thread = new QThread(this);
dbtrad = new dbThread();
dbtrad->moveToThread(thread);

loadAllHistory 2:我就是这样称呼的

我创造了一个信号:

代码语言:javascript
复制
connect(this, SIGNAL(loadAllHistoryS(QString, QString)), dbtrad, SLOT(loadAllHistory(QString, QString)));

就这样叫它:

代码语言:javascript
复制
emit loadAllHistoryS(agentID, agentName);
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-02 09:08:55

问题是,对于innerQuery中的每一行,主线程都会被中断。这破坏了将数据加载到单独的线程中的好处。可能在线程边界上的信号/时隙通信的开销甚至比从数据库加载一行的成本还要高。

我建议收集QList实例中的行-- while循环。完成后,通过一个信号调用将完整的结果推送到主线程:

首先声明一个用于存储历史记录项的简单类:

代码语言:javascript
复制
class HistoryItem {
    public:
        QString channelID;
        /* additonal fields omitted for brevity */
        /* also, private fields with getters and setters would be better */
}

然后,在while循环之前创建这样的对象列表:

代码语言:javascript
复制
QList<HistoryItem*> innerResult;
while (queryInner.next()) {
      /* snip */
      HistoryItem* item = new HistoryItem();
      item.channelId = channelIDInner;
      /* more lines ommited */
      innerResult.append(historyItem);
}
emit historyLoaded(innerResult);

显然,您还需要在worker类中定义一个匹配的信号:

代码语言:javascript
复制
Q_SIGNAL void historyLoaded(QList<HistoryItem*> result);    

另外,正如注释中所指出的,您必须使用QThread::start()启动后台线程。

票数 1
EN

Stack Overflow用户

发布于 2014-12-02 10:00:49

您可以从连续加载中获益:

您只加载将在视图中的元素,并且只在它们被滚动到视图中时才请求下一组元素(或者只是在背景中以更低的速度运行)。

例如,这可以用带有适当信号的向窗口对象添加对象来完成,并让js在末端可见时触发它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27244969

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档