【发布时间】:2018-07-25 09:00:18
【问题描述】:
我正在编写一个从 Reddit 获取提交的小程序。 到目前为止,我的目标只是获取提交并将它们显示在 QML 的 ListView 中。我创建了一个基本的 QML 文件,并创建了一个名为“SubmissionModel”的类,它扩展了“QAbstractListModel”。我使用 PRAW 来获取 reddit 提交,效果很好。
我使用了一个名为 'fetch' 的函数,它使用从 reddit 获得的新提交填充 SubmissionModel 类。然而,这会阻止 QML 视图并使其挂起,直到 'fetch' 函数退出。
我尝试在另一个 Python 线程中运行 'fetch' 函数,这释放了 QML 视图,但遗憾的是 ListView 不再更新。我正在寻找一种可以在 QML 端更新 ListView 的方法,同时从另一个线程运行 fetch 函数。
获取函数:
def fetch():
reddit = init_reddit()
subreddit = reddit.subreddit('LandscapePhotography')
counter = 0
for submission in subreddit.submissions(None, time.time()):
counter += 1
print(
"Counter: {} Submission title: {} , Submission URL: {} ,Created at: {}".format(
counter, submission.title,
submission.url,
datetime.datetime.fromtimestamp(int(submission.created)).strftime('%Y-%m-%d %H:%M:%S')))
model.addSubmission(Submission(submission.title, submission.url,
datetime.datetime.fromtimestamp(int(submission.created)).strftime(
'%Y-%m-%d %H:%M:%S')))
if counter == 400:
break
“提交模型”类:
class SubmissionModel(QAbstractListModel):
NameRole = Qt.UserRole + 1
LinkRole = Qt.UserRole + 2
TimeRole = Qt.UserRole + 3
_roles = {NameRole: b"name", LinkRole: b"link", TimeRole: b"time"}
def __init__(self, parent=None):
super(SubmissionModel, self).__init__(parent)
self._submissions = []
def addSubmission(self, submission):
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self._submissions.append(submission)
self.endInsertRows()
def rowCount(self, parent=QModelIndex()):
return len(self._submissions)
def data(self, index, role=Qt.DisplayRole):
try:
submission = self._submissions[index.row()]
except IndexError:
return QVariant()
if role == self.NameRole:
return submission.name()
if role == self.LinkRole:
return submission.link()
if role == self.CreateTimeRole:
return submission.time()
return QVariant()
def roleNames(self):
return self._roles
没有线程的主函数:
if __name__ == '__main__':
import sys
app = QGuiApplication(sys.argv)
model = SubmissionModel()
view = QQuickView()
view.setResizeMode(QQuickView.SizeRootObjectToView)
ctxt = view.rootContext()
ctxt.setContextProperty('myModel', model)
view.setSource(QUrl('main.qml'))
view.show()
fetch()
sys.exit(app.exec_())
当应用程序像这样运行时 ^^ 它可以工作。 UI 挂起直到 fetch() 完成,当它完成时,UI 将更新为 SubmissionModel 中的所有提交
主线程:
if __name__ == '__main__':
import sys
app = QGuiApplication(sys.argv)
model = SubmissionModel()
view = QQuickView()
view.setResizeMode(QQuickView.SizeRootObjectToView)
ctxt = view.rootContext()
ctxt.setContextProperty('myModel', model)
view.setSource(QUrl('main.qml'))
view.show()
**thread = threading.Thread(target=fetch)**
**thread.start()**
sys.exit(app.exec_())
这使得 'fetch' 函数在另一个线程上运行。虽然它可以正常工作,但每次添加提交时它都无法更新 UI。事实上,用户界面永远不会随着新提交而更新。
我的理解是 addSubmission 函数中的 self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) 和 self.endInsertRows() 方法是为了让 UI 中的 ListView 知道模型已更新。但是,当运行这些方法的函数从另一个线程运行时,这不起作用。有人可以指出我如何从不同的线程更新 ListView 的正确方向吗?
【问题讨论】:
标签: python multithreading pyqt qml pyqt5