gpt4 book ai didi

python - 如何从 python 线程更新 QML ListView?

转载 作者:太空宇宙 更新时间:2023-11-03 14:07:09 25 4
gpt4 key购买 nike

我正在编写一个小程序,用于从 Reddit 获取提交内容。到目前为止,我的目标只是获取提交内容并将其显示在 QML 中的 ListView 中。我创建了一个基本的 QML 文件,并创建了一个名为“SubmissionModel”的类,该类扩展了“QAbstractListModel”。我使用 PRAW 来获取 reddit 提交内容,效果非常好。

我使用一个名为“fetch”的函数,该函数用从 reddit 获取的新提交内容填充 SubmissionModel 类。然而,这会阻塞 QML View 并使其挂起,直到“fetch”函数退出。

我尝试在另一个 Python 线程中运行“fetch”函数,这会释放 QML View ,但遗憾的是 ListView 不再更新。我正在寻找一种方法,可以在从另一个线程运行 fetch 函数的同时更新 QML 端的 ListView。

获取函数:

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

“SubmissionModel”类:

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_())

这使得“fet​​ch”函数在另一个线程上运行。虽然它工作正常,但每次添加提交时都无法更新 UI。事实上,用户界面永远不会随着新提交的内容而更新。

我的理解是 self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())self.endInsertRows() 方法addSubmission 函数的目的是让 UI 中的 ListView 知道模型已更新。但是,当运行这些方法的函数从另一个线程运行时,这不起作用。有人可以指出我如何从不同的线程更新 ListView 的正确方向吗?

最佳答案

建议使用 PyQt 提供的工具来处理线程:

  • QThreadPoolQRunnable:
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"),
)
)

submission = Submission(
submission.title,
submission.url,
datetime.datetime.fromtimestamp(int(submission.created)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
QMetaObject.invokeMethod(
model,
"addSubmission",
Qt.QueuedConnection,
Q_ARG(Submission, submission),
)
QThread.msleep(10)

if counter == 400:
break


class RedditRunnable(QRunnable):
def run(self):
fetch()

然后在main中调用它:

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()

runnable = RedditRunnable()
QThreadPool.globalInstance().start(runnable)

sys.exit(app.exec_())
  • 或者使用信号:
def fetch():
reddit = init_reddit()

subreddit = reddit.subreddit("LandscapePhotography")
counter = 0
message = Message()
message.submissionSignal.connect(model.addSubmission, Qt.QueuedConnection)
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"),
)
)

submission = Submission(
submission.title,
submission.url,
datetime.datetime.fromtimestamp(int(submission.created)).strftime(
"%Y-%m-%d %H:%M:%S"
),
)
message.submissionSignal.emit(submission)
QThread.msleep(10)

if counter == 400:
break
class Message(QObject):
submissionSignal = pyqtSignal(Submission)
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_())

两种方法都可以在下面link中获取.

关于python - 如何从 python 线程更新 QML ListView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48793100/

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