Christian Schultz wrote
I'm trying to add the
PowerBar widget created in the "Custom Widgets" tutorial in a window made in Qt Creator, but it is not appearing.
I made a file named "power_bar.py" with the exact content from the tutorial page, and tested it following the tutorial.
Then, I created a new
MainWindow form in Qt Creator, following the "Embedding custom widgets from Qt Designer" tutorial, put there a widget, and promoted it to
PowerBar from include file
power_bar. The ui content can be seen here: https://pastebin.com/v5i2n0Jr
I then compiled the ui to a file named
main_window.py, which can be seen here:
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(364, 634) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.powerbarWidget = PowerBar(5) self.powerbarWidget.setGeometry(QtCore.QRect(30, 40, 291, 541)) self.powerbarWidget.setObjectName("powerbarWidget") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) from power_bar import PowerBar
I had to edit this file, in the line where it instantiates the
PowerBar, I put a number there because by default it instantiates passing
self.centralWidget as the parameter.
Then I made a file to show the
MainWindow, the content can be seen here:
from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.Qt import * import sys from main_window import Ui_MainWindow class Window(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) if __name__ == "__main__": app = QApplication(sys.argv) w = Window() w.show() sys.exit(app.exec_())
When I run the code, it shows a window, but it doesn't show the widget. If I put a line after the setupUi like: self.ui.powerbarWidget.show() it shows the widget, but it creates another window.
How can I use this widget in a window, like did in the pyqtgraph example?
I guess that you see two windows because at the end of the power_bar.py you have an example of usage not protected by an if statement.
from power_bar import PowerBar from PyQt5.Qt import * import sys class Window(QMainWindow): def __init__(self): super().__init__() self.powerbarWidget = PowerBar(5) self.setCentralWidget(self.powerbarWidget) if __name__ == "__main__": app = QApplication(sys.argv) w = Window() w.show() sys.exit(app.exec_())
Add the if statement at the end of the power_bar.py:
if __name__ == "__main__": app = QtWidgets.QApplication() volume = PowerBar() volume.show() app.exec_()
Else that code will be executed too whenever you import it. The line of code:
from power_bar import PowerBar
shows the first window and enter in the first mainloop. When you close that first window the code after the import is executed, showing another window and entering in another mainloop.
Hello Luca, thank you for your answer, but I didn't understand what I did wrong. To facilitate a bit I uploaded my code in a zip file to this address: https://gofile.io/d/a5jRAf There you all the files I made. I started creating the main_window.ui, where it have only a main window with a widget, which I promoted to PowerBar and pointing the include file to pwer_bar. The file power_bar is there too, and this file onle have the two classes needed (PowerBar and _Bar), and it have no code outside the classes. I compiled the main_window.ui to main_window.py, and I had to edit this file to be able to instatiate the PowerBar class, and as far as I could understand, this code adds this widget to the main window widget. Then I made the main.py file, which instantiates the MainWindow, and there I put a line with self.ui.powerbarWidget.show(), which shows the widget in another window. If I comment out this file, the main window opens but it shows nothing inside.
So, I still don't understand what I did wrong in this code, so I'm asking if anyone can point what I did wrong.
When you notice something strange for example:
- You can't see your widget
- You see your widget in the wrong place
- You see the widget in another window
always check the parent of that widget because the problem could be over there, in particular if you are not using the Qt designer.
Opening the main_window.py file and looking for the instantiation of the PowerBar widget I see:
self.powerbarWidget = PowerBar(5)
The default value for the parent parameter is None, so I've tried to change it in:
self.powerbarWidget = PowerBar(5, parent = self.centralWidget)
And remove the line:
from the file main.py.
In this way it works so the problem is somewhere else.
In the Object inspector of the Qt designer you should see the widget as a child of the centralwidget.
I've tried to generate it and it set the parent correctly.
Could you better describe all the steps that you do before the conversion and after it? Do you manually edit the main_window.py?
As you said, it is passing
self.centralWidget as the parameter. You can modify the power bar class to accept a parent (I should have done this, will fix). But the reason the window floats is that it isn't contained within a layout (which sets the parent automatically).
You can see in the panel that both of these have the red cross through the layout, meaning that there is no layout applied, so the widget won't be contained in the window. If you don't set a parent on it, it will free-float as it's own window. Set a layout on the
centralWidget to avoid this.
The working compiled UI -- had to make the change to the steps param as you noted.
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(364, 634) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) self.horizontalLayout.setObjectName("horizontalLayout") self.powerbarWidget = PowerBar(5) self.powerbarWidget.setObjectName("powerbarWidget") self.horizontalLayout.addWidget(self.powerbarWidget) MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) from power_bar import PowerBar
Thank you Martin for your help, it worked perfectly. I did another try, where I put another widget and promoted it to PowerBar, edited the compiled ui file (changing one widget to have 5 bars and another to 7 bars) and it worked perfectly.
If I may suggest you, you could add this instructions on the tutorial explaining how to include the custom widget in a window with other widgets (buttons, labels) interacting with the custom widget, it would be awesome.
Other thing that would be awesome is a tutorial explaining how to create a composite widget (meaning, a widget made from other widgets), designing this composite in Qt Designer. Your tutorial explains how to do it using only code, and arranging the widgets using only code sometimes is a bit boring. I am (trying) to make a program where I have a "block" of widgets, and this block I will use in other parts of my application. This block is made of some checkboxes, spin boxes and labels. In order to do it (after reading lots of texts and a lot of try and error) I made it to work, where I create a widget in Qt Designer, arrange them the way I want, then I compile them to a py file, then I copy and paste the contets to another class, edit most of the declarations to make them work, and then I can create methods and signals to interact with the composite widget. It worked, but I need to do a lot of work, and probably there is better ways to do it. If you know how to do it and add this information in the tutorial, it would amazing!
[[ discount.discount_pc ]]% OFF for [[discount.description ]] with the code [[ discount.coupon_code ]]