Python 列表更新时更新 ListView
Posted
技术标签:
【中文标题】Python 列表更新时更新 ListView【英文标题】:update ListView when Python list updates 【发布时间】:2019-07-02 19:57:35 【问题描述】:我正在尝试使用 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_())
mainfile.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 更新时刷新?
【问题讨论】:
您的逻辑有点奇怪,甚至很混乱,您可以更详细地解释您的逻辑的每个部分。 我想我理解的是,当您按下文本时,您想重新阅读 .csv 并在 QML 中显示它,对吗? 抱歉,这令人困惑 - 这是我的第一个 PySide/QML 项目,发现了一些可能不是很好但有效的解决方法(除了这个问题)。是的,这基本上就是正在发生的事情 - 当单击按钮时,程序会循环检查由单独程序输出的 csv 文件。它循环到它读取 csv 文件中的第八行。一切正常,但是当 statusOutput.ouputStatus 更改时 ListView 不会更新 换句话说,您是否希望每次按下按钮时只读取文件的前 8 行?如果这是一种解决方法,那么根本问题是什么?是不是每次修改文件时都不需要按键读取8行? 正确,只有前 8 行是相关的,所以那部分是故意的。我希望每次更改 python 时都显示列表,而不管按钮是否按下。我确实计划保留该按钮,但由于我计划添加其他项目 【参考方案1】:您正在组合许多打破Single responsibility principle 的元素,该Single responsibility principle 表示每个类都必须具有定义的函数。
在这种情况下,我只创建了 2 个类:
FileWorker 是一个 QObject,它存在于另一个线程中,它读取文件并发出带有信息的信号。
FileManager 是一个向 QML 公开的 QObject,并具有模型的属性,还有一个允许重新加载数据的 Slot。
main.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)
mainfile.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 列表更新时更新 ListView的主要内容,如果未能解决你的问题,请参考以下文章