【发布时间】:2012-02-10 03:26:06
【问题描述】:
所以基本上我拥有的是一个 Qt 应用程序,它有一个主 GUI 线程和一个工作线程。
工作线程是这样的:
void Client::readResults(int msgqid, pid_t pid)
{
int ret;
msg_t message;
connect(this, SIGNAL(dataReceived(QString)), this, SLOT(updateDisplay(QString)));
connect(this, SIGNAL(doneProcessing(QString)), this, SLOT(updateStatus(QString)));
for (;;)
{
ret = msgrcv(msgqid, &message, MSGSIZE, pid, 0);
if (ret == -1)
{
showStatusBarError("msgrcv");
return;
}
if (ret > 0)
{
emit dataReceived(QLatin1String(message.info));
if (message.is_eof)
{
emit doneProcessing("Done!");
break;
}
}
}
}
它所做的只是从消息队列中读取并发出一个信号,该信号导致来自主 GUI 线程(产生此线程)的 QPlainTextEdit 小部件调用 appendPlainText(message.info) 以便从消息队列接收数据附加到小部件。
问题是,如果我从队列中读取大量数据(它实际上是一个大约 30MB 或更多的文本文件),整个 GUI 会一直挂起,直到工作线程完成。有没有办法让它不挂起,让用户真正看到 QPlainTextEdit 小部件在从工作线程接收数据时滚动?
谢谢!
【问题讨论】:
-
您可以将数据分块提供给 TextEdit 吗? IE。手动将消息拆分为可消化的块?另一个问题是转换为 QLatin1String - 这会创建一个新的临时对象,将来自 messsage.info 的数据复制到其中,然后可能会再次复制它以作为值通过插槽发送。确保您没有进行任何不必要的转换或复制。
-
@AlexanderKondratskiy 在放入消息队列之前,30MB 文件实际上一次读取 256 个字节(由另一个进程)。所以对于每个发出的 dataReceived(),message.info 是 256 个字符。
-
嗯,这很奇怪。我认为问题不在于 QPlainTextEdit,因为我以前用它来打印大型日志。可能是一个愚蠢的建议,但是 Client 对象是在哪里创建的?希望它是在工作线程中实例化的,而不是 GUI 线程,因为所有插槽实际上都会在主线程上触发。
-
@AlexanderKondratskiy 如果您正在与之交谈的人是愚蠢的,这不是一个愚蠢的建议:) 是的,实际上我就是这样做的。我只有 1 个类(客户端),它也是具有信号和插槽的 GUI。我启动 worker 的方式是通过按钮推送槽(即,如果按下 GUI 中的按钮,则调用 QtConcurrent::run(this, &Client::readResults, msgqid, pid))。我到底有多糟糕?
-
也许并没有我想象的那么糟糕。考虑到这一点,我会尽快回复您。