I want to change background of Universal style, so buttons color would match the other stuff, but background property does not working:/ Other properties (accent, foreground, and theme) work as it should. Also on the default style I can change colors of my buttons using palette.button: "#color", but I want to use Universal style on which palette.button: "#color" also does not working
My code:
main.qml:
import QtQuick 2.13
import QtQuick.Window 2.13
import QtQuick.Controls.Universal 2.0
import QtQuick.Controls 2.13
Window {
width: 640
height: 480
visible: true
color: "#786969"
title: qsTr("Hello World")
Universal.accent: "Black" //ok
Universal.background: "Blue" //NOT OK
Universal.foreground: "Yellow" //ok
Universal.theme: Universal.Dark //ok
Button {
id: button
x: 270
y: 138
text: qsTr("Button")
}
CheckBox {
id: checkBox
x: 272
y: 200
text: qsTr("Check Box")
}
Slider {
id: slider
x: 220
y: 264
value: 0.5
}
Switch {
id: switch1
x: 267
y: 334
text: qsTr("Switch")
}
}
main.py:
import sys
import os
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtQuickControls2 import QQuickStyle
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
QQuickStyle.setStyle("Universal")
engine = QQmlApplicationEngine()
engine.load(os.path.join(os.path.dirname(__file__), "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
Printscreen:
Related
I create the design of my app with qt designer and then transform every window to a python file using the command pyuic5 example.ui -o example.py in able to get a Ui_Form class and call it in my program. So every thing is working but now we have changed our design and we get a qml files. My question is how to work with this qml files without changing the concepts of the app. Is there a method like the pyuic5 (to get the Ui_Form class) to transform the qml and use it in pyqt5.
This is an example of the old app:
from main_screen import Ui_Form as Ui_main_screen
class MainScreen(QWidget, Ui_main_screen):
teachButton = False
manageButton = False
utilitiesButton = False
adminButton = False
helpButton = False
systemButton = False
inspectionButton = False
modelSelected = None
def __init__(self):
super(MainScreen, self).__init__()
#QWidget.__init__(self)
self.setupUi(self)
self.trans = QTranslator(self)
self.toLanguage()
self.product()
self.Menu() .....
As you can see, I imported the Ui_Form into the MainScreen class.
Now i want to do the same with the qml file
import QtQuick 2.7
Item {
width:904
height:678
Image {
id: background
source: "images/background.png"
x: 0
y: 1
opacity: 1
}
Image {
id: logo
source: "images/logo.png"
x: 691
y: 34
opacity: 1
}
Image {
id: teach
source: "images/teach.png"
x: 717
y: 154
opacity: 1
}
Image {
id: administration
source: "images/administration.png"
x: 711
y: 410
opacity: 0.49803921568627
}
Image {
id: system
source: "images/system.png"
x: 708
y: 468
opacity: 0.49803921568627
}
Image {
id: utilities
source: "images/utilities.png"
x: 711
y: 353
opacity: 0.49803921568627
}
Image {
id: help
source: "images/help.png"
x: 712
y: 524
opacity: 0.49803921568627
}
Image {
id: teachinf_wizard
source: "images/teachinf_wizard.png"
x: 740
y: 196
opacity: 1
}
Image {
id: inspection
source: "images/inspection.png"
x: 713
y: 295
opacity: 0.49803921568627
}
Image {
id: manage
source: "images/manage.png"
x: 714
y: 239
opacity: 1
}
}
So how to get something like Ui_Form class with qml file
Short Answer:
No it can not be done.
Long Answer:
The .ui are just a set of instructions on how the qwidgets should be displayed, on the other hand, qml is a programming language since they indicate how the objects interact.
The closest thing to what you want is to be able to embed the qml into a QWidget, using for example QQuickWidget:
import os
import sys
import os
from pathlib import Path
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQuickWidgets import QQuickWidget
CURRENT_DIRECTORY = Path(__file__).resolve().parent
def main():
app = QApplication(sys.argv)
widget = QQuickWidget(resizeMode=QQuickWidget.ResizeMode.SizeRootObjectToView)
filename = os.fspath(CURRENT_DIRECTORY / "main.qml")
url = QUrl.fromLocalFile(filename)
widget.setSource(url)
widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I have a qml prototype object ChargeBar defined in ChargeBar.qml. In main project I instance it two times with different ids. I need a slot in Chargebar to send data to. Now I need to write id of target manually in Connections{target: id...} for every instance. Is there any possibility to connect to target automatically?
# This Python file uses the following encoding: utf-8
import os, sys, random
from pathlib import Path
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtCore import QObject, Signal, Slot
APPLICATIONDATA = os.path.join(os.getenv('APPDATA'), "DSController")
class LowLevelControler(QObject):
def __init__(self):
QObject.__init__(self)
nextNumber = Signal(int)
#Slot()
def start(self):
print("giveNumber")
self.nextNumber.emit(random.randint(0, 99))
if __name__ == "__main__":
SERIAL_LLC_RIGHT = "0672FF485550755187034646"
SERIAL_LLC_LEFT = "066AFF575256867067063324"
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
LLC = dict()
LLC["right"] = LowLevelControler()
LLC["left"] = LowLevelControler()
engine.rootContext().setContextProperty("llcRight", LLC["right"])
engine.rootContext().setContextProperty("llcLeft", LLC["left"])
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
main.py <-- entrance
import QtQuick 2.12
import QtQuick.Controls 2.2
import QtQuick.Window 2.12
Window {
id: window
width: 1080
height: 1920
//visibility: "FullScreen"
visible: true
ChargeBar{
id: drawerL
edge: Qt.LeftEdge
llc: llcLeft
}
ChargeBar{
id: drawerR
edge: Qt.RightEdge
llc: llcRight //llcRight=Instance of Python class
Component.onCompleted: llc.nextNumber.connect(reNextNumber)
Connections {
target: drawerR
// PROBLEM: I have to insert target id for every instance manually,
// so I cannot put this passage to ChargeBar.qml */
function onReNextNumber(number) {
print(number)
print("emitted")
}
}
}
Component.onCompleted: drawerR.open()
}
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Drawer {
x:0
y:0
property var llc
signal reNextNumber(int number)
width: 0.66 * window.width
height: window.height
// I want to define Connections here
Button{
id: button
anchors.centerIn: parent
height: 320
width: 320
onClicked: {
llc.start()
}
}
}
ChargeBar.qml
You just have to use the llc object as a target:
ChargeBar.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Drawer {
id: root
property var llc
signal reNextNumber(int number)
width: 0.66 * window.width
height: window.height
Button {
id: button
anchors.centerIn: parent
height: 320
width: 320
onClicked: llc? llc.start(): null
}
Connections {
target: llc
function onNextNumber(n) {
root.reNextNumber(n)
}
}
}
main.qml
import QtQuick 2.12
import QtQuick.Controls 2.2
import QtQuick.Window 2.12
Window {
id: window
width: 1080
height: 1920
visible: true
ChargeBar {
id: drawerL
edge: Qt.LeftEdge
llc: llcLeft
}
ChargeBar {
id: drawerR
edge: Qt.RightEdge
llc: llcRight
// for testing
onReNextNumber: function(number){
console.log("Test", number)
}
}
Component.onCompleted: drawerR.open()
}
I am trying to make QML form for controlling a Servo. So I made a QML form using the QT creator and loaded it using PYQT. From the QML form, I am trying to read a slider value to control the servo. Every time I try to move the slider it says:
AttributeError: 'NoneType' object has no attribute 'value' Aborted
(core dumped)
Here is my pyqt code:
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
dir_path = os.path.dirname(os.path.realpath(__file__))
class MainWindow(QtQml.QQmlApplicationEngine):
def __init__(self):
super(QtQml.QQmlApplicationEngine, self).__init__()
self.load(QtCore.QUrl.fromLocalFile(os.path.join(dir_path, "QML-1.0.qml")))
self.rootContext().setContextProperty("MainWindow", self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.run)
self.timer.start(10)
if self.rootObjects():
# Inherit items from the GUI
self.window = self.rootObjects()[0]
self.text = self.window.findChild(QtCore.QObject, "textField")
self.slider = self.window.findChild(QtCore.QObject, "slider")
def run(self):
print (type(self.slider))
pass
#QtCore.pyqtProperty(int)
def rangeValue(self):
x = self.slider.value()
print x
return 10
if __name__ == '__main__':
app = QtGui.QGuiApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
And here is my qml code:
import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
import QtQuick.Controls.Universal 2.0
import QtGraphicalEffects 1.0
ApplicationWindow {
id: root
width: 900
height: 300
opacity: 1
title: "window"
visible: true
//visibility: Window.FullScreen
visibility: Window.Maximized
Dial {
id: dial
x: 77
y: 60
width: 102
height: 103
wheelEnabled: true
}
Slider {
id: slider
x: 28
y: 220
value: 0.5
onValueChanged: MainWindow.rangeValue(value)
}
Label {
id: label
x: 64
y: 16
width: 128
height: 24
text: qsTr("Servo-1")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
Any help would be appreciated.
Thanks
It seems that you are trying to access a QML element from python which is considered a bad practice so I will not explain where the cause of the error is but I will propose a more stable and recommended solution: Create a QObject, export it to QML and update those properties from QML towards python.
import os
import sys
from PyQt5 import QtCore, QtGui, QtQml
DIR_PATH = os.path.dirname(os.path.realpath(__file__))
class ServoController(QtCore.QObject):
valueChanged = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(ServoController, self).__init__(parent)
self._value = 0
self.valueChanged.connect(self.process_value)
#QtCore.pyqtProperty(float, notify=valueChanged)
def value(self):
return self._value
#value.setter
def value(self, v):
self._value = v
self.valueChanged.emit()
def process_value(self):
print(self.value)
def main():
app = QtGui.QGuiApplication(sys.argv)
engine = QtQml.QQmlApplicationEngine()
servo_controller = ServoController()
engine.rootContext().setContextProperty("servo_controller", servo_controller)
url = QtCore.QUrl.fromLocalFile(os.path.join(DIR_PATH, "QML-1.0.qml"))
engine.load(url)
def on_object_created(obj, objUrl):
if obj is None and url == objUrl:
QtCore.QCoreApplication.exit(-1)
engine.objectCreated.connect(on_object_created, QtCore.Qt.QueuedConnection)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
import QtQuick.Controls.Universal 2.0
import QtGraphicalEffects 1.0
ApplicationWindow {
id: root
width: 900
height: 300
opacity: 1
title: "window"
visible: true
//visibility: Window.FullScreen
visibility: Window.Maximized
Dial {
id: dial
x: 77
y: 60
width: 102
height: 103
wheelEnabled: true
}
Slider {
id: slider
x: 28
y: 220
value: 0.5
onValueChanged: servo_controller.value = value
Component.onCompleted: servo_controller.value = value
}
Label {
id: label
x: 64
y: 16
width: 128
height: 24
text: qsTr("Servo-1")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
In the previous code I created the ServoController class whose function is to map the properties of QML to python such as the value of the slider and call the function process_value when that value changes.
In QML I update the ServoController property when the value of the slider changes and at startup.
I'm trying to access a FileDialog control from the python file that starts the QQmlApplication engine in order to retrieve the file path property. I have set up a signal in the .qml file, however I cannot access the file dialog by id in the python file to set up the slot. The findChild method in application.py returns None. Here is the code:
application.py
import sys
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine, QQmlFileSelector
sys_argv = sys.argv
sys_argv += ['--style', 'material']
app = QGuiApplication(sys_argv)
window = QQmlApplicationEngine()
window.load("QML/main.qml")
fileDialog = window.findChild(QQmlFileSelector, "fileDialog")
print(fileDialog)
app.exec_()
Page1.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2
Page {
width: 600
height: 400
header: Label {
text: qsTr("Prepare Data")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Qt.application.font.pixelSize * 2
padding: 10
}
Button {
text: qsTr("Load data")
anchors.centerIn: parent
onClicked: fileDialog.visible = true
padding: 10
}
signal folderSelected()
FileDialog {
id: fileDialog
selectFolder: true
title: qsTr("Select the data directory")
folder: shortcuts.home
onAccepted: {
parent.folderSelected()
}
}
}
main.qml
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
ApplicationWindow{
visible: true
title: qsTr("Main window")
width: 1000
height: 800
Material.theme: Material.Light
Material.accent: Material.Orange
SwipeView {
id: swipeView
anchors.fill: parent
Page1 {
}
Page2 {
}
Page3 {
}
}
}
In an old answer explain in the section Pushing References to QML how to update some python object from QML, that methodology is the one recommended by Qt and it is the one that should be used now. With your current method you need to establish an objectname that can be problematic in many cases.
So the solution is to create a QObject that we export to QML and update the qproperty, this will emit a signal that we connect to a slot where we can do the logic that we want. On the other hand FileDialog returns a url, so the property must be a QUrl:
main.qml
import os
import sys
from PySide2 import QtCore, QtGui, QtQml
class FileManager(QtCore.QObject):
file_url_Changed = QtCore.Signal(QtCore.QUrl)
def __init__(self, parent=None):
super(FileManager, self).__init__(parent)
self._file_url = QtCore.QUrl()
def get_file_url(self):
return self._file_url
def set_file_url(self, file_url):
if self._file_url != file_url:
self._file_url = file_url
self.file_url_Changed.emit(self._file_url)
file_url = QtCore.Property(QtCore.QUrl, fget=get_file_url, fset=set_file_url, notify=file_url_Changed)
#QtCore.Slot(QtCore.QUrl)
def on_file_url_changed(file_url):
print(file_url.toLocalFile())
if __name__ == '__main__':
sys.argv += ['--style', 'material']
app = QtGui.QGuiApplication(sys.argv)
file_manager = FileManager()
file_manager.file_url_Changed.connect(on_file_url_changed)
engine = QtQml.QQmlApplicationEngine()
engine.rootContext().setContextProperty("file_manager", file_manager)
file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "QML", "main.qml")
engine.load(QtCore.QUrl.fromLocalFile(file))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
Page1.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Dialogs 1.2
Page {
width: 600
height: 400
header: Label {
text: qsTr("Prepare Data")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Qt.application.font.pixelSize * 2
padding: 10
}
Button {
text: qsTr("Load data")
anchors.centerIn: parent
onClicked: fileDialog.visible = true
padding: 10
}
FileDialog {
id: fileDialog
selectFolder: true
title: qsTr("Select the data directory")
folder: shortcuts.home
onAccepted: {
file_manager.file_url = fileDialog.fileUrl // <---
}
}
}
I’m beginner on programming in python and qml and I'm doing a project
My project need to have many UI forms I’m using qml to create these UI
Lets say we have Form A,B,C and when application load I need it to open Form A and form A contain button which I click and open Form B and Form A close, Form B it have button which I click it open form C and that form B close… Plis help me on these project
main.py
import sys
from PyQt5.QtCore import QObject, QUrl, Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQml import QQmlApplicationEngine
if __name__ == "__main__":
app = QApplication(sys.argv)
engine = QQmlApplicationEngine()
ctx = engine.rootContext()
ctx.setContextProperty("main", engine)
ctx2 = engine.rootContext()
ctx2.setContextProperty("main", engine)
engine.load('form1.qml')
win = engine.rootObjects()[0]
def pageC():
engine.load('form3.qml')
win2 = engine.rootObjects()[0]
button1 = win2.findChild(QObject, "form3")
button1.clicked.connect(pageC)
win2.show()
def newPage():
engine.load('form2.qml')
win = engine.rootObjects()[0]
win.show()
button1=win.findChild(QObject, "form2")
button1.clicked.connect(newPage)
win.show()
sys.exit(app.exec_())
form1.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.5
Window {
visible: true
width: 200
height: 200
title: qsTr("Hello World")
maximumHeight: 200
minimumHeight: 200
maximumWidth: 200
minimumWidth: 200
Button {
id: button1
objectName: "form2"
x: 22
y: 71
width: 157
height: 59
text: qsTr("Page a")
onClicked: callPageB()
}
}
form2.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.5
Window {
visible: true
width: 200
height: 200
title: qsTr("Hello World")
maximumHeight: 200
minimumHeight: 200
maximumWidth: 200
minimumWidth: 200
Button {
id: button1
objectName: "form3"
x: 22
y: 71
width: 157
height: 59
text: qsTr("Page B")
onClicked: callPageC()
}
}
form3.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.5
Window {
visible: true
width: 200
height: 200
title: qsTr("Hello World")
maximumHeight: 200
minimumHeight: 200
maximumWidth: 200
minimumWidth: 200
Button {
id: button1
x: 22
y: 71
width: 157
height: 59
text: qsTr("Page C")
}
}
When adding qmls to QQmlApplicationEngine we can get through rootObjects(), so to do this I simply created the following class, but there are certain restrictions, each button inside the Window should have the objectName as the name of the file and must Be the children of Window:
example.qml:
Window {
...
Button {
objectName: "example"
}
...
}
In the next part this class with the name of your qmls.
class Engine(QQmlApplicationEngine):
counter = 0
def __init__(self, qmls, parent=None):
QQmlApplicationEngine.__init__(self, parent)
[self.load("{}.qml".format(qml)) for qml in qmls]
for i, root in enumerate(self.rootObjects()):
if root != self.rootObjects()[0]:
root.close()
if root != self.rootObjects()[-1]:
button= root.findChild(QObject, qmls[i])
button.clicked.connect(self.closeAndOpen)
def closeAndOpen(self):
self.rootObjects()[self.counter].close()
self.counter += 1
self.rootObjects()[self.counter].show()
if __name__ == "__main__":
app = QApplication(sys.argv)
engine = Engine(['form1', 'form2', 'form3'])
sys.exit(app.exec_())