form.ui editing has no effect
-
Hello,
I am testing Python development with the QtCreator. With the wizzard I have created a project with QMainWindow. The main.py script starts indeed with the creating of the window - that works.With the Designer I put some menu entries widget on the window. The problem is that no changes will be shown in the running program. I get always a simple QMainWindow.
What can be the problem ?
Andreas
-
@jsulm said in form.ui editing has no effect:
@Andy314 How exactly do you use the ui file? Do you generate Python code from it or do you load it directly?
I took the original code that the wizzard has generated. I changed only the WindowTitle.
from PySide2.QtWidgets import QApplication, QMainWindow from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader class TMainWindow(QMainWindow): def __init__(self): super(TMainWindow, self).__init__() self.load_ui() self.setWindowTitle("Qt Test") def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": app = QApplication([]) widget = TMainWindow() widget.show() sys.exit(app.exec_())
-
@Andy314 said in form.ui editing has no effect:
ui_file.open(QFile.ReadOnly)
You should check whether open succeeds. Maybe the file is not found?
-
@jsulm said in form.ui editing has no effect:
@Andy314 said in form.ui editing has no effect:
ui_file.open(QFile.ReadOnly)
You should check whether open succeeds. Maybe the file is not found?
```
ok=ui_file.open(QFile.ReadOnly)
gives True !
-
@jsulm said in form.ui editing has no effect:
@Andy314 Don't know. Are you sure you're really editing the file which is loaded at runtime?
I am very sure, because I checked the path and the raw content of the ui-file.
``` w=loader.load(ui_file, self) errorString=loader.errorString()
errorString is empty ?
-
@jsulm said in form.ui editing has no effect:
@Andy314 Is
os.path.join(os.path.dirname(__file__), "form.ui")
the same path you're editing?
Yes ! This path had a mixing of \ / , what Qt usually doesn't bother.
Nevetheless I wrote out the path explicit in the code, but it does help.I renamed the file in the folder. That gave an other error, so that I am sure that it is the right file.
-
@Andy314 said in form.ui editing has no effect:
errorString is empty ?
What tells you there has been any error?
loader.errorString()
will be empty if there is no error. You are supposed to check the return result to see if there is any error, before you try to look aterrorString()
:w = loader.load(ui_file, self) if not w: errorString = loader.errorString() print(errorString) return
-
@JonB said in form.ui editing has no effect:
@Andy314 said in form.ui editing has no effect:
errorString is empty ?
What tells you there has been any error?
loader.errorString()
will be empty if there is no error. You are supposed to check the return result to see if there is any error, before you try to look aterrorString()
:w = loader.load(ui_file, self) if not w: errorString = loader.errorString() print(errorString) return
That was a quess of me. The return result is ok and not NULL (or how ever this is called in Python).
-
@JonB said in form.ui editing has no effect:
@Andy314
Then you don't have any error on theloader.load()
. I don't know whether that still leaves you with any other issue.An chance to debug loader.load() ?
Maybe its once again a versions problem as so often in Python as I found out.
I use QtCreator 4.13.2 on Qt 5.15.1 (probably doesnt matter)
and Python 3.8.7 64-bit with PySide 5.15.1.
(with Python 3.9, PySide its doesnt work anyway because of shiboken dll missing.)Can some body give me a combination that is been in use and works, please ?
(Creator I would not change.) -
@eyllanesc said in form.ui editing has no effect:
@Andy314 please share the .ui file
Here is it.
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>PySideTest2</class> <widget class="QMainWindow" name="PySideTest2"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>PySideTest2</string> </property> <widget class="QWidget" name="centralwidget"> <widget class="QPushButton" name="pushButton"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>75</width> <height>23</height> </rect> </property> <property name="text"> <string>PushButton</string> </property> </widget> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>21</height> </rect> </property> <widget class="QMenu" name="menuFile"> <property name="title"> <string>File</string> </property> <addaction name="actionTest"/> </widget> <widget class="QMenu" name="menuExit"> <property name="title"> <string>Exit</string> </property> </widget> <addaction name="menuFile"/> <addaction name="menuExit"/> </widget> <widget class="QStatusBar" name="statusbar"/> <action name="actionTest"> <property name="text"> <string>Test</string> </property> </action> </widget> <resources/> <connections/> </ui>
-
@Andy314 QUiLoader does not populate a widget like PyQt5's loadUi does but instead creates a new instance, and that can be verified by modifying to the following:
def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) widget = loader.load(ui_file, self) widget.show() ui_file.close()
You will see that 2 windows are shown, one parent of the other but it will not be shown inside the window because the QMainWindow has the Qt::Window flag enabled by default. If you want to use QUiLoader then the class must behave like a controller:
import sys import os from PySide2.QtWidgets import QApplication from PySide2.QtCore import QFile, QObject from PySide2.QtUiTools import QUiLoader class Controller(QObject): def __init__(self): super(Controller, self).__init__() self.load_ui() self.window.setWindowTitle("Qt Test") def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) self.window = loader.load(ui_file) ui_file.close() def show(self): self.window.show() if __name__ == "__main__": app = QApplication([]) widget = Controller() widget.show() sys.exit(app.exec_())
-
@eyllanesc
Wow, you are great ! Thank you very much for the help :-)With this tip, I found a good page of the problematic and want share it.
https://www.learnpyqt.com/blog/pyqt5-vs-pyside2/If I understand it correct the problem is that the wizzard does not generate the correct code for the PySide modul. It generate from the code/class structure code for PyQt. But this code would not not run in PyQt because of the wrong uiloader function (uic.loadUi("mainwindow.ui", self should ist be).
Its false for both modues.Hm, PyQt I "did not have on my screen."
Should I maybe use PyQt instead of PySide.
What is recommended ? -
@Andy314 The problem is not the functions or libraries but your misunderstanding of what each function is for. In the case of loadUi if a second parameter is passed to it then it will take it as a toplevel unlike QUiLoader which does not. So the solution is: read in detail the docs of each function you use.
-
@eyllanesc said in form.ui editing has no effect:
@Andy314 The problem is not the functions or libraries but your misunderstanding of what each function is for. In the case of loadUi if a second parameter is passed to it then it will take it as a toplevel unlike QUiLoader which does not. So the solution is: read in detail the docs of each function you use.
I come for C++ and thought it works just like that. I think a lot of PySide beginner struggle with this problem. I will check the docu and find a way.
I am happy that we found a solution. -
@Andy314 said in form.ui editing has no effect:
I come for C++ and thought it works just like that
[Like what?] Then you will be pleased to see that PySide2's
QUiLoader::load()
is defined/works exactly like in C++, QWidget *QUiLoader::load(QIODevice *device, QWidget *parentWidget = nullptr).Which is quite different from PyQt5's
PyQt5.uic.loadUi()
, which works differently from C++....