Heesung Yang
[문제 해결] Qt Quick 2 / QML - TypeError: Cannot read property
현상
아래 코드 실행 후 동적으로 List Item을 추가한 후, 삭제 시 다음과 같은 에러 메시지가 출력됨
main.qml:45: TypeError: Cannot read property 'width' of null
-
main.py
import os from pathlib import Path import sys from PySide2.QtGui import QGuiApplication from PySide2.QtQml import QQmlApplicationEngine if __name__ == "__main__": app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml")) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_())
-
main.qml
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { id: root width: 640 height: 480 title: "Hello, world" visible: true ListModel { id: myModel property int autoIndex: 1 } Column { anchors.fill: parent spacing: 10 Button { anchors.right: parent.right text: "Add Item" onClicked: { myModel.append({'number': myModel.autoIndex}) myModel.autoIndex += 1 } } ListView { id: listView width: 350 height: 400 anchors.horizontalCenter: parent.horizontalCenter spacing: 10 clip: true model: myModel delegate: Rectangle { width: parent.width height: 50 color: "white" Button { anchors.right: parent.right anchors.rightMargin: 15 anchors.horizontalCenter: parent.horizontalCenter text: qsTr("remove: ") + number onClicked: { myModel.remove(index) } } } } } }
원인
https://doc.qt.io/qt-5/qml-qtquick-listview.html#example-usage
Delegates are instantiated as needed and may be destroyed at any time. As such, state should never be stored in a delegate. Delegates are usually parented to ListView’s contentItem, but typically depending on whether it’s visible in the view or not, the parent can change, and sometimes be null. Because of that, binding to the parent’s properties from within the delegate is not recommended. If you want the delegate to fill out the width of the ListView, consider using one of the following approaches instead:
ListView {
id: listView
// ...
delegate: Item {
// Incorrect.
width: parent.width
// Correct.
width: listView.width
width: ListView.view.width
// ...
}
}
해결 방안
delegate item(Rectangle)의 width 속성을 상위 컴포넌트와 동일하게 설정하고 싶은 경우, parent
키워드 대신 상위 컴포넌트의 id를 사용한다.
-
main.qml
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { // ...생략 Column { // ...생략 Button { // ...생략 } ListView { id: listView // ...생략 model: myModel delegate: Rectangle { width: listView.width // parent.width -> listView.width 변경 // ...생략 Button { // ...생략 } } } } }