python - Python 列表更新时更新 ListView

标签 python qml pyside2

我正在尝试使用 PySide 根据 csv 文件中的数据更新 QML 中的 ListView。 csv 文件由外部程序更新,因此我设置了一个循环来循环从该文件中获取数据。

我能够将数据输入 Python 并打印出来,但我认为我的错误是信号/槽问题,而且它根本没有在 QML 中更新。

main.py:

def importSimStatus(statusOutput):
    with open(r'status output.csv','r') as readFile:

        dummyList2 = statusOutput.outputStatus

        i = 0

        for j in range(8):
            statusOutput.setOutputStatus("", j)

        csvReader = csv.reader(readFile)
        for row in csvReader:


            statusOutput.setOutputStatus(row[0], i)
            dummyList2 = statusOutput.outputStatus

            i += 1


def checkSimOutput():

    for out in range(8):
        statusOutput.setOutputStatus("", out)

    simResults = []

    dummyList = statusOutput.outputStatus
    while (dummyList[7] == ""):
        try:
            importSimStatus(statusOutput)


        except:
            pass
        time.sleep(1)

        print(statusOutput.outputStatus)

class CheckSimOutput(QRunnable):
    def run(self):
        checkSimOutput()


class OutputData(QObject):

    statusSig = Signal(list)


    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.m_outputStatus = []        

    def resizeOutputStatus(self, i):
        for x in range(i):
            self.m_outputStatus.append("")

    @Property(list, notify=statusSig)
    def outputStatus(self):
        return self.m_outputStatus

    @outputStatus.setter
    def setOutputStatus(self, text, i):
        if self.m_outputStatus[i] == text:
            return
        self.m_outputStatus[i] = text
        self.statusSig.emit(self.m_outputStatus)

class Settings(QObject):


    simWorkAround = Signal(int)

    def __init__(self, parent=None):
        QObject.__init__(self, parent)

        self.m_simWorkAround = 0

    @Property(int, notify=simWorkAround)
    def simWorkaround(self):
        return self.m_simWorkAround

    @simWorkaround.setter
    def setSimWorkaround(self, num):
        if self.m_simWorkAround == num:
            return
        self.m_simWorkAround = num
        self.simWorkAround.emit(self.m_simWorkAround)

if __name__ == '__main__':

    app = QGuiApplication(sys.argv)

    settings = Settings()
    statusOutput = OutputData()

    statusOutput.resizeOutputStatus(8)

    def simThread():
        simOutRunnable = CheckSimOutput()
        QThreadPool.globalInstance().start(simOutRunnable)


    model = QStringListModel()
    model.setStringList(statusOutput.outputStatus)

    engine = QQmlApplicationEngine()

    engine.rootContext().setContextProperty("settings", settings)
    engine.rootContext().setContextProperty("myModel", model)

    engine.load(QUrl.fromLocalFile('mainfile.qml'))
    if not engine.rootObjects():
        sys.exit(-1)

    settings.simWorkAround.connect(simThread)
    statusOutput.statusSig.connect(model.setStringList(statusOutput.outputStatus))


    sys.exit(app.exec_())

主文件.qml:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.1


ApplicationWindow {

visible: true
width: 640
height: 480
title: qsTr("Main Program")

       Button {
           text: qsTr("Start Draft")
           anchors.top: parent.top
           anchors.topMargin: 21
           anchors.horizontalCenterOffset: 0
           anchors.horizontalCenter: parent.horizontalCenter
           onClicked: settings.simWorkaround = settings.simWorkaround + 1
       }



        ListView{
            id: listView
            x: 0
            width: 200
            height: 150
            anchors.top: parent.top
            anchors.topMargin: 55
            anchors.horizontalCenter: parent.horizontalCenter
            contentWidth: 0
            model: myModel
                //anchors.fill: parent
            delegate: Text { text: model.display }
        }


    }

如上所述,我可以在从 csv 文件导入列表后打印该列表。我还可以通过添加如下项目来“预加载”列表:

statusOutput.setOutputStatus("foo",0)
statusOutput.setOutputStatus("bar",1)

在“engine.rootContext().setContextProperty("myModel", model)”之前,我可以看到“foo”和“bar”的列表,但单击按钮运行循环时没有任何反应.

如何让 ListView 在 statusOutput 更新时刷新?

最佳答案

您正在组合许多违反 Single responsibility principle 的元素这表明每个类必须有一个定义的函数。

在本例中,我只创建了 2 个类:

  • FileWorker 是一个 QObject,它存在于另一个线程中,它读取文件并发出带有信息的信号。

  • FileManager 是一个暴露给 QML 的 QObject,具有模型属性,还有一个允许重新加载数据的插槽。

ma​​in.py:

import os
import csv
from functools import partial
from PySide2 import QtCore, QtGui, QtQml

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class FileWorker(QtCore.QObject):
    linesChanged = QtCore.Signal(list)

    @QtCore.Slot(str)
    def read_csv(self, filename):
        lines = []
        with open(filename, "r") as f:
            csv_reader = csv.reader(f)
            for i, row in enumerate(csv_reader):
                if i > 7:
                    break
                lines.append(row[0])
        self.linesChanged.emit(lines)


class FileManager(QtCore.QObject):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.m_model = QtCore.QStringListModel(self)
        self.m_thread = QtCore.QThread(self)
        self.m_thread.start()
        self.m_worker = FileWorker()
        self.m_worker.moveToThread(self.m_thread)
        self.m_worker.linesChanged.connect(self.updateModel)

    @QtCore.Property(QtCore.QAbstractItemModel, constant=True)
    def model(self):
        return self.m_model

    @QtCore.Slot()
    def load(self):
        filename = os.path.join(CURRENT_DIR, "status output.csv")
        wrapper = partial(self.m_worker.read_csv, filename)
        QtCore.QTimer.singleShot(0, wrapper)

    def clean(self):
        self.m_thread.quit()
        self.m_thread.wait()

    @QtCore.Slot(list)
    def updateModel(self, lines):
        self.m_model.setStringList(lines)


if __name__ == "__main__":
    import sys

    app = QtGui.QGuiApplication(sys.argv)

    engine = QtQml.QQmlApplicationEngine()

    filemanager = FileManager()
    filemanager.load()

    engine.rootContext().setContextProperty("filemanager", filemanager)
    filename = os.path.join(CURRENT_DIR, "mainfile.qml")
    engine.load(QtCore.QUrl.fromLocalFile(filename))
    if not engine.rootObjects():
        sys.exit(-1)

    res = app.exec_()

    filemanager.clean()

    sys.exit(res)

ma​​infile.qml:

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Window 2.2


ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Main Program")

    Button {
        text: qsTr("Start Draft")
        anchors.top: parent.top
        anchors.topMargin: 21
        anchors.horizontalCenterOffset: 0
        anchors.horizontalCenter: parent.horizontalCenter
        onClicked: filemanager.load()
    }

    ListView{
        id: listView
        width: 200
        height: 150
        anchors.top: parent.top
        anchors.topMargin: 55
        anchors.horizontalCenter: parent.horizontalCenter
        contentWidth: 0
        model: filemanager.model
        // anchors.fill: parent
        delegate: Text { text: model.display }
    }
}

关于python - Python 列表更新时更新 ListView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56859268/

相关文章:

python - 安装在Google Colab中的Google云端硬盘中的相对路径

qt - QML:有条件地设置属性组的不同属性

c++ - Qt-5.14.0:QML下的Vulkan导致std::system_error::互斥锁失败

python - 为什么 QTabBar 给我错误的索引号?

python - 如何使用 QStyledItemDelegate 绘制()

python - 如何从第 x 行开始写入 CSV?

python - 在 PyQt(或 PySide)中编码时,我应该使用 Python 函数还是等效的 Qt 函数?

qt - Qt Quick 的单元测试

python - 如何设置QMenu撕下窗口标题?

python - 如何删除具有多个子文件夹的主文件夹内的所有文件?