gpt4 book ai didi

multithreading - 如何通过 QSqlQueryModel 进行异步查询?

转载 作者:行者123 更新时间:2023-12-03 13:12:41 24 4
gpt4 key购买 nike

我希望通过 QSqlQueryModel 查询 SQL 数据库(PyqQt 5/Qt 5.2) 异步,因此 GUI 不会阻塞。如何实现?也许通过多线程?请提供如何执行此操作的代码。如果异步使用 QSqlQueryModel 不实用,请随时提供替代方案(尽管应该可以与 QTableView 一起使用)。

我的(同步)代码当前如下所示。主脚本 bin/app.py 加载 gui/__init__.py 并执行其 main方法。这反过来使用 gui.models.Table从数据库加载数据。问题是 gui.models.Table同步查询数据库并同时锁定 GUI。

斌/应用程序.py:

import os.path
import sys

sys.path.insert(0, os.path.abspath(os.path.join(
os.path.dirname(__file__), "..")))

import gui


if __name__ == "__main__":
gui.main()

桂/ __init__ .py:
import sys
import os.path
from PyQt5 import uic
from PyQt5 import QtCore, QtWidgets

from gui import models


class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi(os.path.join(os.path.dirname(__file__), 'app.ui'), self)
self.tableView.setModel(models.Table(self))


def main():
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()

gui/models.py:
import os.path
from PyQt5.QtCore import *
from PyQt5.QtSql import *


class Table(QSqlQueryModel):
def __init__(self, parent=None):
super(Table, self).__init__(parent)

pth = os.path.abspath(os.path.join(os.path.dirname(__file__), "..",
"test.sqlite"))
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(pth)
if not db.open():
raise Exception("Couldn't open database '{}'".format(pth))
try:
self.setQuery("select * from Test")
finally:
db.close()

最佳答案

不幸的是,Qt(或其他任何人)使用的典型数据库驱动程序是同步的。不幸的是,Qt View 不知道如何处理外部线程中的模型。

因此,该解决方案需要一个 shim 代理模型,子类化 QIdentityProxyModel .实现的第一步是使用阻塞 QMetaObject::invokeMethod 填充源模型的所有方法调用。来电。这只是为了正确,如果还不是异步的话。它只是向存在于另一个线程中的模型公开一个安全接口(interface)。

下一步是在某些功能上提供异步胶合板。假设您要制作 data方法异步。你要做的是:

  • 对于每个角色,都有一个由模型索引键入的变量值缓存。
  • dataChanged来自源模型的信号,缓存所有角色中更改的所有值。 data调用需要在模型的线程中排队 - 稍后会详细介绍。
  • data ,如果有缓存命中,则返回它。否则返回一个空变量并将 data 排队调用模型的线程。

  • 您的代理应该有一个名为 cacheData 的私有(private)方法将从排队的调用中调用。在另一个答案中,我有 detailed how to queue functor calls in another thread .利用这一点,您的数据调用队列方法可能如下所示:
    void ThreadsafeProxyModel::queueDataCall(const QModelIndex & index, int role) {
    int row = index.row();
    int column = index.column();
    void * data = index.internalPointer();
    postMetacall(sourceModel()->thread(), [this, row, column, data, role]{
    QVariant data = sourceModel()->data(createIndex(row, column, data), role);
    QMetaObject::invoke(this, "cacheData",
    Q_ARG(QVariant, data), Q_ARG(int, role),
    Q_ARG(int, row), Q_ARG(int, column), Q_ARG(void*, data));
    });
    }

    这只是一个草图。它会相当复杂,但肯定是可行的,并且仍然保持真实模型的语义。

    关于multithreading - 如何通过 QSqlQueryModel 进行异步查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22482599/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com