gpt4 book ai didi

python - 如何从任意长度的 Python3 字符串数组构建 QML ListElements

转载 作者:行者123 更新时间:2023-12-01 00:09:58 28 4
gpt4 key购买 nike

我是 QML、QtQuick 和 Python 的新手。我想使用 QML 显示文件列表(完整路径)。看来我应该使用 ListView 和 ListElements。我发现的示例和教程都使用硬编码且非常简单的列表数据。我不明白如何从这些例子转向更现实的东西。

如何使用后端的 Python 字符串数组填充 QML UI 显示的列表?

字符串数组的长度是任意的。我希望列表项是可点击的(可能像 QML url 类型)。他们将打开操作系统针对该文件/url 类型的默认应用程序。

我的后端代码与此类似:

import sys
from subprocess import Popen, PIPE
import getpass
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtCore import Qt, QCoreApplication, QObject, pyqtSlot
from PyQt5.QtQml import QQmlApplicationEngine

class Backend(QObject):

basepath = '/path/to/files'
list_files_cmd = "find " + basepath + " -type f -readable"

myfiles = Popen(list_files_cmd, shell=True, stdout=PIPE, stderr=PIPE)
output, err = myfiles.communicate()
# the output is a Byte literal like this: b'/path/to/file1.txt\n/path/to/file2.txt\n'. Transform into a regular string:
newstr = output.decode(encoding='UTF-8')
files_list = newstr.split('\n')
for file in files_list:
print(file)

if __name__ == '__main__':

backend = Backend()

QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
engine = QQmlApplicationEngine('view.qml')
engine.rootContext().setContextProperty("backend", backend)
sys.exit(app.exec_())

现在,我只是将 files_list 字符串数组从后端打印到控制台,但目标是使用该字符串数组填充 UI 中的 QML 列表。

files_list 的内容示例如下:

['/path/to/files/xdgr/todo.txt', '/path/to/files/xdgr/a2hosting.txt', '/path/to/files/xdgr/paypal.txt', '/path/to/files/xdgr/toggle.txt', '/path/to/files/xdgr/from_kty.txt', '/path/to/files/xdgr/feed59.txt', '/path/to/files/one/sharing.txt', '/path/to/files/two/data.dbx', '']

(我需要弄清楚如何处理该数组末尾的空字符串。)

我的 QML 的粗略轮廓(尽我目前的能力)如下:

import QtQml.Models 2.2
import QtQuick.Window 2.2
import QtQuick 2.2
import QtQuick.Controls 1.3
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3

ApplicationWindow {
visible: true
TabView {
anchors.fill: parent
Tab {
title: "Files"
anchors.fill: parent
ListView {
id: mListViewId
anchors.fill: parent
model: mListModelId
delegate : delegateId
}
ListModel {
id: mListModelId
// I would like backend.files_list to provide the model data
}
}
}
Component.onCompleted: {
mListModelId.append(backend.files_list)
}
}

我发现的最相关的问题是这些,但它们没有解决我的问题:

qt - 动态创建 QML ListElement 和内容 - 堆栈内存溢出 Dynamically create QML ListElement and content

qt - QML ListElement 传递字符串列表 - 堆栈内存溢出 QML ListElement pass list of strings

最佳答案

您不需要使用 ListModel 来填充 ListView,因为 the docs指出模型可以是列表:

model : model

This property holds the model providing data for the list.

The model provides the set of data that is used to create the items in the view. Models can be created directly in QML using ListModel, XmlListModel or ObjectModel, or provided by C++ model classes. If a C++ model class is used, it must be a subclass of QAbstractItemModel or a simple list.

(强调我的)

我还推荐Data Models .

在这种情况下,可以通过pyqtProperty显示列表。另一方面,不要使用 subprocess.Popen(),因为它会阻塞,导致 GUI 卡住,而应使用 QProcess

import os
import sys

from PyQt5.QtCore import (
pyqtProperty,
pyqtSignal,
pyqtSlot,
QCoreApplication,
QObject,
QProcess,
Qt,
QUrl,
)
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine


class Backend(QObject):
filesChanged = pyqtSignal()

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

self._files = []

self._process = QProcess(self)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
self._process.setProgram("find")

@pyqtProperty(list, notify=filesChanged)
def files(self):
return self._files

@pyqtSlot(str)
def findFiles(self, basepath):
self._files = []
self.filesChanged.emit()
self._process.setArguments([basepath, "-type", "f", "-readable"])
self._process.start()

def _on_readyReadStandardOutput(self):
new_files = self._process.readAllStandardOutput().data().decode().splitlines()
self._files.extend(new_files)
self.filesChanged.emit()


if __name__ == "__main__":

QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)

backend = Backend()

engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("backend", backend)

current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "view.qml")
engine.load(QUrl.fromLocalFile(filename))

if not engine.rootObjects():
sys.exit(-1)

sys.exit(app.exec_())

view.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Controls 1.4

ApplicationWindow {
visible: true
width: 640
height: 480
TabView {
anchors.fill: parent
Tab {
title: "Files"
ListView {
id: mListViewId
clip: true
anchors.fill: parent
model: backend.files
delegate: Text{
text: model.modelData
}
ScrollBar.vertical: ScrollBar {}
}
}
}
Component.onCompleted: backend.findFiles("/path/to/files")
}

您还可以使用 QStringListModel。

import os
import sys

from PyQt5.QtCore import (
pyqtProperty,
pyqtSignal,
pyqtSlot,
QCoreApplication,
QObject,
QProcess,
QStringListModel,
Qt,
QUrl,
)
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine


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

self._model = QStringListModel()

self._process = QProcess(self)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
self._process.setProgram("find")

@pyqtProperty(QObject, constant=True)
def model(self):
return self._model

@pyqtSlot(str)
def findFiles(self, basepath):
self._model.setStringList([])
self._process.setArguments([basepath, "-type", "f", "-readable"])
self._process.start()

def _on_readyReadStandardOutput(self):
new_files = self._process.readAllStandardOutput().data().decode().splitlines()
self._model.setStringList(self._model.stringList() + new_files)


if __name__ == "__main__":

QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)

backend = Backend()

engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty("backend", backend)

current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "view.qml")
engine.load(QUrl.fromLocalFile(filename))

if not engine.rootObjects():
sys.exit(-1)

sys.exit(app.exec_())

view.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Controls 1.4

ApplicationWindow {
visible: true
width: 640
height: 480
TabView {
anchors.fill: parent
Tab {
title: "Files"
ListView {
id: mListViewId
clip: true
anchors.fill: parent
model: backend.model
delegate: Text{
text: model.display
}
ScrollBar.vertical: ScrollBar {}
}
}
}
Component.onCompleted: backend.findFiles("/path/to/files")
}

关于python - 如何从任意长度的 Python3 字符串数组构建 QML ListElements,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59698564/

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