Reputation: 440
I am trying to extend QML with qmlRegisterType. I have a python class - PyQml.py, main.qml files and boilerplate code for it. Problem is I cant reference(import) PyQml object in main.qml file, I get an error --> QML module not found (PyQml) .
So far I have determined QML_IMPORT_PATH variable paths. Since I was hopelles, I created folder named PyQml with PyQml.py in it in one of the paths but still no success. Furthermore, I cant find *.pro file in Qt Creator project. I suppose I should add another path to my custom object to it.
PyQml.py
class PyQml(QObject):
def __init__(self, parent=None):
super().__init__(parent)
# Initialise the value of the properties.
self._name = ''
self._shoeSize = 0
# Define the getter of the 'name' property. The C++ type of the
# property is QString which Python will convert to and from a string.
@Property('str')
def name(self):
return self._name
# Define the setter of the 'name' property.
@name.setter
def name(self, name):
self._name = name
# Define the getter of the 'shoeSize' property. The C++ type and
# Python type of the property is int.
@Property(int)
def shoeSize(self):
return self._shoeSize
# Define the setter of the 'shoeSize' property.
@shoeSize.setter
def shoeSize(self, shoeSize):
self._shoeSize = shoeSize
qmlengine.py
import sys
import sqlite3
from PySide2 import QtCore, QtGui, QtWidgets, QtQuick
from PySide2.QtCore import Qt,QUrl
from PySide2.QtQml import QQmlApplicationEngine,qmlRegisterType
from PySide2.QtGui import QGuiApplication
from ViewModel import PyQml
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
print(QQmlApplicationEngine.importPathList(engine))
ctx = engine.rootContext()
ctx.setContextProperty("qmlapp", engine) #the string can be anything
qmlRegisterType(PyQml.PyQml, 'People', 1, 0, 'Person');
engine.load('Documents/ctmd/Qml/main.qml')
win = engine.rootObjects()[0]
win.show()
sys.exit(app.exec_())
main.qml
import QtQuick 2.0
import QtQuick.Controls 1.4
import PyQml 1.0 ---- Error QML module not found ( PyQml)
ApplicationWindow {
menuBar: MenuBar {
Menu {
title: "File"
MenuItem { text: "Open..." }
MenuItem { text: "Close" }
}
Menu {
title: "Edit"
MenuItem { text: "Cut" }
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}
}
Grid {
columns: 3
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
Rectangle { color: "cyan"; width: 50; height: 50 }
Rectangle { color: "magenta"; width: 10; height: 10 }
}
}
Project folder tree
Qml
-main.qml
PyQml.py
qmlengine.py
PyQml is just a sample class, at the end of day I want to pass custom data I calculated in python ( x,y coordinates ) and plot that data with qml
Upvotes: 3
Views: 2611
Reputation: 440
I found out if I simply ignore this error
in qml window everything works fine. I even tried reinstalling IDE, error stays. Thank you for clarification.
Upvotes: 0
Reputation: 243955
TL;DR; There is no solution to eliminate the error message since it is a limitation of QtCreator with Qt for Python. But QtCreator is only an IDE so it does not need to work there, instead you just have to run the code from the console/CMD:
python /path/of/script.py
You have the following errors:
When you register a QObject with qmlRegisterType "People" is the name of the package in QML and "Person" is the name of the component, so you should not use PyQml in the import unless you change the registry parameters.
QtCreator/QtQuickDesigner still has limitations with Python support, so the message: "Qml module not found (FooPackage)" is a sample of this. As the developers of Qt for Python/PySide2 point out in future versions they will add new features but it is currently not possible.
I see that the structure that you indicate in your publication does not match your project since for example you indicate that the main.qml is in the QML folder that is at the same level as qmlengine.py but in the load you use "Documents/ctmd/Qml/main.qml".
PySide2 has limitations with the Property decorator and its setter since it is not recognized by QML, instead it uses the extensive declaration: name_of_property = Property(type_of_property, fget = getter_of_property, ...)
If a Qt Property with a setter then it must have an associated signal.
Considering the above, the solution is:
├── PyQml.py
├── Qml
│ └── main.qml
└── qmlengine.py
qmlengine.py
import os
import sys
from PySide2.QtCore import QUrl
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
import PyQml
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
qmlRegisterType(PyQml.PyQml, "People", 1, 0, "Person")
engine = QQmlApplicationEngine()
ctx = engine.rootContext()
ctx.setContextProperty("qmlapp", engine) # the string can be anything
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "Qml/main.qml")
engine.load(QUrl.fromLocalFile(filename))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
PyQml.py
from PySide2.QtCore import Property, Signal, QObject
class PyQml(QObject):
nameChanged = Signal(str)
shoeSizeChanged = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
# Initialise the value of the properties.
self._name = ""
self._shoeSize = 0
# Define the getter of the 'name' property. The C++ type of the
# property is QString which Python will convert to and from a string.
def get_name(self):
return self._name
# Define the setter of the 'name' property.
def set_name(self, name):
if self._name != name:
self._name = name
self.nameChanged.emit(name)
name = Property(str, fget=get_name, fset=set_name, notify=nameChanged)
# Define the getter of the 'shoeSize' property. The C++ type and
# Python type of the property is int.
def get_shoeSize(self):
return self._shoeSize
# Define the setter of the 'shoeSize' property.
def set_shoeSize(self, shoeSize):
if self._shoeSize != shoeSize:
self._shoeSize = shoeSize
self.shoeSizeChanged.emit(shoeSize)
shoeSize = Property(
int, fget=get_shoeSize, fset=set_shoeSize, notify=shoeSizeChanged
)
main.qml
import QtQuick 2.0
import QtQuick.Controls 1.4
import People 1.0
ApplicationWindow {
visible: true
Person{
name: "foo"
shoeSize: 10
}
menuBar: MenuBar {
Menu {
title: "File"
MenuItem { text: "Open..." }
MenuItem { text: "Close" }
}
Menu {
title: "Edit"
MenuItem { text: "Cut" }
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}
}
Grid {
columns: 3
spacing: 2
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
Rectangle { color: "cyan"; width: 50; height: 50 }
Rectangle { color: "magenta"; width: 10; height: 10 }
}
}
Upvotes: 3