Я сделал простой список в Qt Qml. Я использую PySide2 и QStringListModel для заполнения списка. Когда список больше, как в этом простом примере, щелкнув printBtn (который должен изменить цвет текста на зеленый) в Qt Qml, получите следующую ошибку: «TypeError: значение не определено и не может быть преобразовано в объект». Если список содержит меньше элементов, вроде все нормально. Как изменить мой код, чтобы не было этой проблемы в будущем.
Возможно, это ошибка в Qt? Есть ли обходной путь?
См. мой простой фрагмент кода ниже:
Питон:
import sys
from PySide2.QtCore import Qt, QStringListModel, QObject, Signal, Slot
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
class Main(QObject):
clicked = Signal()
def __init__(self, parent=None):
super(Main, self).__init__(parent)
@Slot()
def justClicking(self):
self.clicked.emit()
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
main = Main()
engine.rootContext().setContextProperty("main", main)
data = ["London", "New York", "Paris", "Tokyo", "Sydney", "Madrid", "Mumbai", "Istanbul", "Bangkok", "Moscow", "Toronto", "Rome", "Shanghai", "Rio de Janeiro", "Seoul", "Berlin", "Cape Town", "Amsterdam", "Los Angeles", "San Francisco", "Cairo", "Barcelona", "Buenos Aires", "Melbourne", "Athens", "Vancouver", "Dubai", "Prague", "Edinburgh", "Singapore"]
model = QStringListModel()
model.setStringList(data)
context = engine.rootContext()
context.setContextProperty("myModel", model)
engine.load("main.qml")
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
Qml-код:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
Window {
visible: true
color: "#161515"
width: 640
height: 480
title: qsTr("Listview Example")
Rectangle {
id: rectangle
x: 51
y: 63
width: 539
height: 143
color: "#ffffff"
ListView {
id: listView
anchors.fill: parent
model: myModel
currentIndex: 0
delegate: Rectangle {
id: dlg
width: listView.width
height: 25
color: index === listView.currentIndex ? "lightgrey" : "#00000000"
radius: 10
property alias colorOfText: titleText.color
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
Text {
id: titleText
text: model.display
font.pixelSize: 18
color: "black"
padding: 5
}
Connections {
target: main
function onClicked() {
var myListItemObjectC = listView.contentItem.children[listView.currentIndex]
myListItemObjectC.colorOfText = "green"
}
}
}
}
}
Button {
id: printBtn
x: 286
y: 241
width: 69
height: 35
text: qsTr("Print")
onClicked: {
main.justClicking()
}
}
}
Я пытался не использовать QStringListModel, безуспешно пытался добавить их в ListModel. Я ценю любую помощь!
Можете ли вы поделиться своим кодом? @СтивенКуан
Я также перенес на PySide6, и он не работает, все еще сталкиваясь с той же проблемой.
Я запускал его на Ubuntu с pyside6/Qt6.4.0 и на macOS с pyside6/Qt6.5.0. Я разместил свой код в качестве ответа, но мне неловко, поскольку код на самом деле является вашим кодом с очень незначительными изменениями.
Я перенес ваше приложение на PySide6. Похоже, он работает с минимальными изменениями кода.
Вот main.py
со ссылками PySide2, измененными на PySide6:
import sys
from PySide6.QtCore import Qt, QStringListModel, QObject, Signal, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
class Main(QObject):
clicked = Signal()
def __init__(self, parent=None):
super(Main, self).__init__(parent)
@Slot()
def justClicking(self):
self.clicked.emit()
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
main = Main()
engine.rootContext().setContextProperty("main", main)
data = ["London", "New York", "Paris", "Tokyo", "Sydney", "Madrid", "Mumbai", "Istanbul", "Bangkok", "Moscow", "Toronto", "Rome", "Shanghai", "Rio de Janeiro", "Seoul", "Berlin", "Cape Town", "Amsterdam", "Los Angeles", "San Francisco", "Cairo", "Barcelona", "Buenos Aires", "Melbourne", "Athens", "Vancouver", "Dubai", "Prague", "Edinburgh", "Singapore"]
model = QStringListModel()
model.setStringList(data)
context = engine.rootContext()
context.setContextProperty("myModel", model)
engine.load("main.qml")
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
Вот main.qml
с импортом Qt5, замененным импортом Qt6:
Я переработал ваш main.qml
, чтобы сохранить список «зеленых» предметов. Нам нужно сделать это, потому что вы не можете получить доступ к делегатам напрямую, так как Qt будет создавать и уничтожать делегаты по требованию. Нам нужно полагаться на видимых делегатов и на то, что они привязаны к чему-то, что мы можем показать.
import QtQuick
import QtQuick.Controls
import QtQuick.Window
Window {
visible: true
color: "#161515"
width: 640
height: 480
title: qsTr("Listview Example")
property list<string> green
Rectangle {
id: rectangle
x: 51
y: 63
width: 539
height: 143
color: "#ffffff"
ListView {
id: listView
anchors.fill: parent
model: myModel
currentIndex: 0
delegate: Rectangle {
id: dlg
width: listView.width
height: 25
color: index === listView.currentIndex ? "lightgrey" : "#00000000"
radius: 10
property var modelText: model.display
property alias colorOfText: titleText.color
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
Text {
id: titleText
text: modelText
font.pixelSize: 18
color: green.indexOf(modelText) !== -1 ? "green" : "black"
padding: 5
}
}
}
}
Button {
id: printBtn
x: 286
y: 241
width: 69
height: 35
text: qsTr("Print")
onClicked: {
main.justClicking()
}
}
Connections {
target: main
function onClicked() {
if (green.indexOf(listView.currentItem.modelText) === -1) {
green.push(listView.currentItem.modelText);
}
}
}
}
Чтобы лучше понять жизненный цикл ваших делегатов, рассмотрите возможность добавления следующего кода к вашему делегату:
Component.onCompleted: console.info(`Construction for ${model.display} ${index}`);
Component.onDestruction: console.info(`Destruction for ${model.display} ${index}`);
Затем, когда вы прокручиваете свой ListView вверх и вниз, вы увидите, что делегаты создаются и уничтожаются. По этой причине вы не можете программно получить доступ к своим делегатам, поскольку они могут существовать или не существовать.
Вот скриншот вашего приложения:
Привет! Хорошо, если вы выберете последний элемент «Сингапур» и нажмете кнопку «Печать», разве вы не получите сообщение об ошибке «TypeError: значение не определено и не может быть преобразовано в объект» в консоли и текст «Сингапур» не станет зеленым? @Стивен Куан
Теперь, когда я понял ваш main.qml
, я переписал его часть. Смотрите обновленный main.qml
и соответствующее объяснение.
Я перенес ваше приложение на pyside6, и оно работает.