void TableWidget::load()
{
QSqlQuery query(_db);
query.setForwardOnly(true);
query.prepare("SELECT * FROM " + _name);
query.exec();
int lines = query.size();
int columns = query.record().count();
setRowCount(lines);
int row = 0;
while (query.next()) {
for(int column = 0; column < columns; column++)
setItem(row, column, new QTableWidgetItem(query.value(column).toString()));
row++;
}
resizeColumnsToContents();
}
我正在使用上面的代码将数据从MySQL加载到QTableWidget。数据有多大?大约1k5行~100列(通过互联网)。它以一种显着的方式冻结了应用程序用户(图形)界面。如何使它顺利?
我有心思(作为最后的手段)。但是,由于这已经是一个插槽,我认为它是在单独的线程中进行的(不是吗?)。
答案 0 :(得分:0)
因为这已经是一个插槽,我认为它正在单独进行 线程(isn&#39; t?)
不,Qt应用程序通常在一个线程中工作,特别是所有GUI代码必须在主线程中运行。听起来你很困惑什么&#34;异步代码&#34;在Qt意味着。它通常(除非你自己使用线程,或者使用明确记录的类来在内部使用线程)意味着你编写插槽并连接信号,然后在调用插槽时它会做它的事情并尽可能快地返回,这一切都在一个线程中工作。没有插槽同时执行(因此没有线程问题)。如果插槽需要很长时间才能执行,那么您将获得GUI冻结,因为它位于该一个线程中。
让小部件插槽在另一个线程中执行通常是一个坏主意:它无法调用任何小部件自己的方法,它们不是线程安全的,所以它是很容易通过不小心调用错误的方法来创建错误。使用Qt信号和插槽在线程之间进行通信,如果您添加要从不同线程调用的任何方法,请特别注意您在其中执行的操作。
对问题代码的大多数直接修复都是创建新的QObject
子类,并将那个load()
方法放在那里,然后将整个对象移动到另一个线程中运行。然后,代替上面显示的setItem()
调用,发出包含必要信息的信号,并将其连接到TableWidget
中的一个插槽,该插槽执行setItem()
(只要连接类型是自动或排队的,线程之间的信号将由Qt事件循环处理。
要了解Qt线程的工作原理,您可以read the docs starting here,但您也可以使用<{3}}中的建议小心地 来移动您的load()
方法到一个新的子类,然后在另一个线程中执行。
一旦有效,你应该每个信号发出更多数据以提高效率:可能是一行数据,可能是更大的数据块,甚至可能所有一个信号中的数据,具体取决于多少你拥有的数据。 Qt容器是写时复制的,所以在线程之间传递它们作为信号参数不是额外的开销,无论它们有多大(它们都不会被复制,除非你修改它们)。