I am running code on a Windows 7 VM with Qt Creator and I am getting a module "material" is not installed error when running my code. It is initialized with Python 3.8 using Pyside6. My Qt Creator is version 4.15.0
This is the QML code:
import QtQuick 2.0
import QtQuick.Controls 2.12
Item {
width: 640
height: 480
visible: true
Rectangle {
id: rectangle
x: 232
y: 220
width: 200
height: 200
color: "#c96565"
}
}
This is the Python script: It is a modified version of one of the example default scripts.
import os
import sys
import urllib.request
import json
from pathlib import Path
import PySide6.QtQml
from PySide6.QtQuick import QQuickView
from PySide6.QtCore import QStringListModel, Qt, QUrl
from PySide6.QtGui import QGuiApplication
if __name__ == '__main__':
#Set up the application window
app = QGuiApplication(sys.argv)
view = QQuickView()
view.setResizeMode(QQuickView.SizeRootObjectToView)
#Load the QML file
qml_file = Path(__file__).parent / "main.qml"
view.setSource(QUrl.fromLocalFile(os.fspath(qml_file.resolve())))
#Show the window
if view.status() == QQuickView.Error:
sys.exit(-1)
view.show()
#execute and cleanup
app.exec()
del view
I didn't use Qt Quick Control elements in the QMl yet though. Even if I do have a Quick Control elements there the same thing happens. However, if I remove/comment out the import statement for Qt Quick Controls below, the application runs fine. I've tried changing the version number next to quick controls too without success.
UPDATE: It seems that not being able to find the module is a path issue, so I brute forced the path into the qml file by adding this line to the top: import "./Controls.2" as QtQuickControls
And I copied pasted the Controls.2 folder that is nested in the PySide6 folder into the root directory of this project. The error I get now is
The plugin <filepath to qtquickcontrols2plugin.dll> uses incompatible Qt library. <5.15.0> [release] import "./Controls.2" as QtQuickControls
I figured it out: I don't need to brute force the path in; in the .pydevproject file of your python project, make sure you add in the full path to PySide6 because for some reason the system cannot find it without the path.
Something like this:
<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
<path>\path\to\your\python\venv\or\folder\Lib\site-packages\PySide6</path>
</pydev_pathproperty>
If that doesn't work, try calling the Material module directly:
import QtQuick.Controls.Material 2.12
Related
I am trying to create a circular guage using Qml in Python as a QQuickWidget.
I am unable to do so as I receive the Error CircularGauge.qml:18:9: NumberAnimation is not a type
I am working on windows, where I have added C:\Qt\Tools\QtCreator\bin\qml to my path.
I have copied CircularGauge.qml exactly as is from example found on the Qt site doc.qt.io
to solve this issue I tried adding import QtQuick 2.0 to the CircularGauge.qml file, but then I receive the error CircularGauge is instantiated recursively
My python code is as follows:
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PySide6.QtQuick import QQuickView, QQuickWindow, QSGRendererInterface
from PySide6.QtQuickWidgets import QQuickWidget
if __name__ == '__main__':
app = QApplication()
QQuickWindow.setGraphicsApi(QSGRendererInterface.OpenGL)
widget = QQuickWidget()
widget.setSource('CircularGauge.qml')
layout = QVBoxLayout(widget)
widget.show()
sys.exit(app.exec())
I have confirmed this works with other qml exampls,
for example if I replace widget.setSource('CircularGauge.qml') with widget.setSource('view.qml')
where view.qml is:
import QtQuick
Rectangle {
id: main
width: 200
height: 200
color: "green"
Text {
text: "Hello World"
anchors.centerIn: main
}
}
I get the desired result of a qml file loaded into a QQuickWidget
How can I load the CircularGauge in the same way?
I have a qt quick pyside application .I had a question before,but now another proplem is there .Just a empty window appears and then in application window I see below message.Although I have another qt quick application that I written that in c++ and there is no problem displaying it, this message is displayed!,This application is in python(pyside6)
I use Qt 6.0.2,Python 3.9.2,Qt Creator 4.14.1 and Pyside6
Failed to create vertex shader: Error 0x80070057: The parameter is incorrect.
Failed to build graphics pipeline state
*main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id:mainWindow
width: 1000
height: 580
visible: true
title: qsTr("JooyaTrader")
Rectangle{
width: 152
height: 62
anchors.fill: parent
color: "red"
}
}
main.py
import sys,os
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
import PySide6
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
The problem is caused because the backend that Qt Quick uses for rendering does not work for your case, either because there are missing libraries or the version is not according to what Qt expects. In that one solution is to set the QT_QUICK_BACKEND in "software" making the rendering do it Qt Quick 2D Renderer:
os.environ["QT_QUICK_BACKEND"] = "software"
app = QGuiApplication(sys.argv)
For more information read Scene Graph Adaptations.
I am trying to write my own QQuickItems that use the SceneGraph to draw shapes as if it the parent Item was a Canvas. I am using PySide6 and Python. During my attempts I found a bug in PySide6, which was earlier reported. I downloaded the patch that fixed it and it seems to be ok now (https://bugreports.qt.io/browse/PYSIDE-1345).
My program now compiles and runs, but the node is not painted. If I understand the documentation correctly, I need to do three things to have a custom QQuickItem painted:
Inherit from QQuickItem
Override updatePaintNode
Set the ItemHasContents flag
I did all that, registered my type, added it in QML and made sure it has non-zero dimensions. Unfortunately, it still does not get paited. I do not know what to do next.
Here's the minimal working example:
main.py
# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys
from PySide6.QtGui import QGuiApplication, QColor
from PySide6.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide6.QtQuick import QQuickItem, QSGGeometryNode, QSGGeometry, QSGFlatColorMaterial
class JustItem(QQuickItem):
def __init__(self, parent=None):
super().__init__(parent)
self.setFlag(QQuickItem.ItemHasContents)
def updatePaintNode(self, node, update_data):
if node is None:
node = QSGGeometryNode()
geometry = QSGGeometry(QSGGeometry.defaultAttributes_Point2D(), 4)
geometry.setDrawingMode(QSGGeometry.DrawTriangles)
vertex_data = geometry.vertexDataAsPoint2D()
vertex_data[0].set(10, 10)
vertex_data[1].set(100, 10)
vertex_data[2].set(100, 100)
vertex_data[3].set(10, 100)
material = QSGFlatColorMaterial()
material.setColor(QColor(255, 0, 0, 127))
node.setGeometry(geometry)
node.setMaterial(material)
return node
if __name__ == "__main__":
qmlRegisterType(JustItem, "PythonTypes", 1, 0, "JustItem")
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())
And QML:
import QtQuick
import QtQuick.Window
import PythonTypes 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
JustItem {
}
}
The result is an empty white window. When I resize it, it segfaults.
This is a bug in PySide 2. Currently it is not possible to draw your custom QQuickItems in PySide 2.
The bug is discussed in more detail here: https://forum.qt.io/topic/116585/qsggeometry-does-not-work-on-pyside2/16
There's also a bug report, which has a proposed fix. The fix causes segmentation fault: https://bugreports.qt.io/browse/PYSIDE-1345
Unfortunately, if you want to draw custom QQuickItems you either need to write them in C++ or use another GUI framework entirely.
The objective:
I'm writing a Gui front-end for a Matplotlib-based library for nested samples (pip install anesthetic if you want to have a look).
How I would go about it in C++: My previous experience with QML was a C++ program, where instead of going into QML to find a canvas to render to, I created a C++ object, registered it in QML's type system, and had it behave as a QtQuick controls widget. As far as I know this is the recommended way of doing things: have all the rendering be done in QML, and have all the business-end-logic in C++.
THe best approach and why I can't do it: This approach doesn't work here. AFAIK you can only implement custom QML using C++, and I need for the program to be pure-ish Python (for others to be able to maintain it) some JS is accessible and QML is pretty easy to understand and edit, so I had no objections (C++ was a hard no).
what I got working: I have a working implementation of what I want. It was all in one file. So, naturally I wanted to split the canvas to which I'm drawing to into a separate file: figure.qml. Trouble is, I can't seem to find the object by that name whenever it's loaded from a separate file (the next step is to use a Loader, because the Figure is quite clunky).
I have a two-file project with view.qml being the root, and a component in Figure.qml.
The trouble is, it only works if I load the thing with objectName: "component" in view.qml and not in Component.qml.
So how does one findChild in Pyside for an objectName that's in a different .qml file?
MWE:
main.py
import sys
from pathlib import Path
from matplotlib_backend_qtquick.backend_qtquickagg import FigureCanvasQtQuickAgg
from matplotlib_backend_qtquick.qt_compat import QtGui, QtQml, QtCore
def main():
app = QtGui.QGuiApplication(sys.argv)
engine = QtQml.QQmlApplicationEngine()
displayBridge = DisplayBridge()
context = engine.rootContext()
qmlFile = Path(Path.cwd(), Path(__file__).parent, "view.qml")
engine.load(QtCore.QUrl.fromLocalFile(str(qmlFile)))
win = engine.rootObjects()[0]
if win.findChild(QtCore.QObject, "figure"):
print('success') # This fails
app.exec_()
view.qml
import QtQuick.Controls 2.12
import QtQuick.Windows 2.12
ApplicationWindow{
Figure {
}
}
Figure.qml
import QtQuick.Controls 2.12
import QtQuick 2.12
Component{
Rectangle{
objectName: "figure"
}
}
Component is used to define a QML element, it does not instantiate it, therefore you cannot access the object. Creating a Figure.qml is equivalent to creating a Component, and you are creating a Component inside another Component.
The solution is not to use Component:
Figure.qml
import QtQuick.Controls 2.12
import QtQuick 2.12
Rectangle{
objectName: "figure"
}
But it is not recommended to use objectName since, for example, if you create multiple components, how will you identify which component it is? o If you create the object after a time T, or use Loader or Repeater you will not be able to apply that logic. Instead of them it is better to create a QObject that allows obtaining those objects:
from PySide2 import QtCore
import shiboken2
class ObjectManager(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._qobjects = []
#property
def qobjects(self):
return self._qobjects
#QtCore.Slot(QtCore.QObject)
def add_qobject(self, obj):
if obj is not None:
obj.destroyed.connect(self._handle_destroyed)
self.qobjects.append(obj)
print(self.qobjects)
def _handle_destroyed(self):
self._qobjects = [o for o in self.qobjects if shiboken2.isValid(o)]
# ...
object_manager = ObjectManager()
context = engine.rootContext()
context.setContextProperty("object_manager", object_manager)
qmlFile = Path(Path.cwd(), Path(__file__).parent, "view.qml")
engine.load(QtCore.QUrl.fromLocalFile(str(qmlFile)))
# ...
import QtQuick.Controls 2.12
import QtQuick 2.12
Rectangle{
Component.onCompleted: object_manager.add_qobject(this)
}
I am having trouble displaying a simple image into my application.
Here's the main.py:
import sys
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtCore import QObject, QUrl
if __name__ == '__main__':
sys.argv += ['--style', 'material']
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine('basic.qml')
sys.exit(app.exec_())
And the basic.qml:
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
ApplicationWindow {
visible: true
width: 200
height: 400
title: qsTr("Hello World")
Material.theme: Material.Light
Material.accent: Material.Orange
Column {
anchors.centerIn: parent
Button {
width: 200; height:50;
font.capitalization: Font.MixedCase
text: qsTr("Button Name")
objectName: "button_obj_name"
highlighted: true
Material.background: Material.Orange
}
Image{
width: 100; height: 100
fillMode: Image.PreserveAspectFit
source: "logo_name.jpg"
}
}
}
In the application window it seems that space is allocated but nothing is displaying.
[logo_name.jpg is located in the same folder where basic.qml and main.py are in ]
Your code looks right. I was having a similar problem on my windows box. Code that worked on the raspberry did not work on the windows machine. Removing and reinstalling PyQt5 go it working again.
pip3 uninstall pyqt5
It had something to do with the image I was trying to display(as #Jason R. Mick mentioned),I believe that the image I was trying to use was converted by changing it's extension name.
As a sanity check can you please post the image you're trying to
display & image/listing of folder contents? – Jason R. Mick
You should better check current path.
You can print out the current path with sys.argv[0].
After getting the path, copy your image file to that path.
Then, run again.
I also think this is not a problem of source code, but development environment.