QSqlQuery(MySQL)到QTableWidget冻结用户界面

时间:2015-07-20 02:09:43

标签: qt

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列(通过互联网)。它以一种显着的方式冻结了应用程序用户(图形)界面。如何使它顺利?

我有心思(作为最后的手段)。但是,由于这已经是一个插槽,我认为它是在单独的线程中进行的(不是吗?)。

1 个答案:

答案 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容器是写时复制的,所以在线程之间传递它们作为信号参数不是额外的开销,无论它们有多大(它们都不会被复制,除非你修改它们)。