PyQt: Always on top - python

This is on PyQt4, Linux and Python 2.5
Can I make PyQt set my window "always on top" over other applications?
For example, in GTK i use the property: Modal.
Now, in PyQt I am using a QWidget, but, I can't find a way to do that.
Any ideas??

Pass the QMainWindow the WindowStaysOnTopHint window flag (or use setWindowFlags).
As in the name, this is a hint to the windowing manager (not a hard guarantee).
Simplest possible example:
import sys
from PyQt4 import QtGui, QtCore
class mymainwindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
app = QtGui.QApplication(sys.argv)
mywindow = mymainwindow()
mywindow.show()
app.exec_()

setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
setwindowaFlags is a method that can call it from form object and just take one parameter is a constant QtCore.Qt.WindowStaysOnTopHint that refer to make your form Stays On Top

Related

What is the advantage of converting a ui file to Python code vs loading it directly? [duplicate]

This question already has answers here:
Benefits of using pyuic vs uic.loadUi
(2 answers)
Closed 1 year ago.
Is there an advantage to:
Converting it to python
pyside6-uic mainwindow.ui > ui_mainwindow.py
and then
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtCore import QFile
from ui_mainwindow import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
vs. loading it directly like so: ?
ui_file = QFile("mainwindow.ui")
ui_file.open(QFile.ReadOnly)
loader = QUiLoader()
window = loader.load(ui_file)
window.show()
I suppose the app will start faster/run faster if converted beforehand.
Is there anything else to consider?
There are two main differences:
in terms of loading, QUiLoader theoretically adds a bit of overhead because it has to build the ui everytime, meaning that it has to parse the XML file, create the node structure, and then create the UI with all its contents; the uic file, instead, directly creates the UI, skipping the first two steps above;
QUiLoader can only create a new widget based on the UI file, while the uic method allows to use an already existing base widget, and the child widgets can be added to it;
The latter point is probably the most important: using QUiLoader you cannot directly use subclassing for the loaded UI.
For instance, if you create a main window in Designer, QUiLoader will return a new QMainWindow. You cannot (or, at least, you should not) do the following:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
ui_file = QFile("mainwindow.ui")
ui_file.open(QFile.ReadOnly)
loader = QUiLoader()
window = loader.load(ui_file, self)
And you should not even try to make the returned object as central widget, like the following:
self.setCentralWidget(window)
because the result would be to have a QMainWindow inside a QMainWindow, which is discouraged and unsupported, and might also create problems when using the standard features of a QMainWindow (typically, docks and toolbars).
The only alternative would be to create a basic form widget in Designer and use that as central widget, with the downside that menus, docks and toolbars have to be created by code.
For PySide, the only possibility that allows full subclassing is to use the pyside-uic method and then eventually use the multiple inheritance (but that's not a requirement, as composition is a valid alternative anyway):
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
On the other hand, PyQt provides the loadUi function that actually does what setupUi does, since the second argument is not the parent widget, but the widget itself, and the contents of the ui will be loaded into it:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi("mainwindow.ui", self)
As far as I know, PySide doesn't provide anything similar yet.
Note that loading the ui at runtime has two issues anyway, and for both bindings:
there is no prior sanity checking, if the UI file is corrupted or invalid, or has unsupported features/properties due to version mismatch, it might not load properly or even crash;
when using an IDE, there's no code completion for ui objects, since they are only loaded at runtime;
Those are not major issues, but it's important to be aware of them anyway.

Custom External Widget does not show up [duplicate]

This question already has answers here:
QtDesigner changes will be lost after redesign User Interface
(2 answers)
Closed 1 year ago.
I want to create a GUI for a python file I wrote, so I downloaded PyQt5 and Qt Designer. When I exported my first try of the Qt Designer project I realized that the not PyQt5 was used but PySide2. What is the reason for this?
Till then everything worked fine, and I wanted to start some specific things like bringing a widget I created into a scrollArea. For this I created a custom widget and created a .ui and a .py. But they don't show up if I try to call them. Also the generated code for python looks like this:
from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint, QRect, QSize, QUrl, Qt)
from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, QFontDatabase, QIcon, QLinearGradient, QPalette, QPainter, QPixmap, QRadialGradient)
from PySide2.QtWidgets import *
class Ui_Form(object):
def setupUi(self, Form):
if Form.objectName():
Form.setObjectName(u"Form")
Form.resize(640, 480)
self.widget = QWidget(Form)
self.widget.setObjectName(u"widget")
self.widget.setGeometry(QRect(270, 190, 77, 44))
self.verticalLayout = QVBoxLayout(self.widget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.label = QLabel(self.widget)
self.label.setObjectName(u"label")
self.verticalLayout.addWidget(self.label)
self.pushButton = QPushButton(self.widget)
self.pushButton.setObjectName(u"pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.retranslateUi(Form)
QMetaObject.connectSlotsByName(Form)
# setupUi
def retranslateUi(self, Form):
Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
self.label.setText(QCoreApplication.translate("Form", u"TextLabel", None))
self.pushButton.setText(QCoreApplication.translate("Form", u"PushButton", None))
# retranslateUi
As you can see, my widget does not inherit from "QWidget" but from "object". Also, my widget has no "init" but a "setupUi".
Why is that?
If I change to inherit from "object" to "QWidget" the code runs bot the widget does not show up. Also, when I try to show only the widget itself with the following code, it does not show up.
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = Ui_Form()
w.show()
sys.exit(app.exec_())
Empty Widget
I tried to search around and did not find anything that helped me out, so I'm asking my questions here.
Can somebody please explain to me why all this is happening like it is right now and how I can make them widgets show up and add them to a scrollArea?
Thanks in advance!
The reason for having PySide instead of PyQt is that you used the pyside-uic tool instead if pyuic, which is a tool that creates very similar files but using PyQt.
Both PySide and PyQt are python bindings to Qt, and they work almost seamlessly, except from some implementation differences; this means two important things:
they cannot be used together;
most of the times you can just change the import statement at the beginning of each script to switch between them (from PyQt5 import... instead of from PySide2 import...);
They also have different licenses, so you need to check that if you want to create a commercial program.
About the created object, that is what is generally called a "form class", and it's used to "set up" a Qt widget instance: it's not a widget, but some sort of utility.
In order to properly use those generated scripts (which should never be manually modified), you must import them and then use them as a separate instance that will create the UI or as a base class for multiple inheritance, which is the most common method; the following example assumes that you used pyuic (not pyside-uic) to generate a file named mywidget.py, and creates a QWidget using the multiple inheritance:
from PyQt5 import QtWidgets
from mywidget import Ui_Form
class MyWidget(QtWidgets.QWidget, Ui_Form):
def __init__(self):
super().__init__()
self.setupUi(self)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
Read more about this in the official guidelines about using Designer.
Some more insight can be found in the answers to this related post

PyQT with QT Creator

I am trying to develop a small gui using PySide and the QT Creator.
As the base implementation, I have choosen a QMainWindow.
The problem is that adding any elements to that MainWindow inside the Editor results in an empty window when I run the code.
The initially generated python code looks like this:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.load_ui()
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 = MainWindow()
widget.show()
sys.exit(app.exec_())
I know that loader.load(ui_file, self) returns a widget. My solution was:
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, self)
self.window.show()
ui_file.close()
if __name__ == "__main__":
app = QApplication([])
widget = MainWindow()
#widget.show() <<<<<<--- removing this
sys.exit(app.exec_())
This works for me but this clearly cannot be the way this is supposed to work.
I am confused on why QT Creator gives me this non-working templaet.
Furthermore I am curious on how custom functions should be implemented.
When clicking on the clicked() slot for a button, it tells me
No ui_form.h found! (translated)
I ended up writing the functions into my MainWindow class like this:
self.window.menuopen_button.clicked.connect(lambda x: self.menu_animation(x))
self.window.minimise_button.clicked.connect(lambda x: self.menu_buttons('minimise'))
Your initial code only loads the UI file into the QUiLoader object - you don't do anything else with it. When you call widget.show(), you're calling the QMainWindow's show method which is a default window (and, hence, empty) since you haven't added the loaded widget to it.
Your solution similarly loads the UI but displays it via the widget object's show method. However, you're not amending it to your main window, so you're basically tossing your main window and just using the widget.
There are a couple ways to correctly accomplish what you want:
One way would be to, as #musicamante suggested, add the loaded UI widget to your MainWindow object (and by the way, this is supported by PySide2: https://doc.qt.io/archives/qtforpython-5.12/PySide2/QtUiTools/QUiLoader.html - the example in the detailed description shows exactly how to do this).
Or the other way, which I prefer, would be to use the uic utility, PySide2-uic, in the build process to generate a UI Python class based on the UI file.
The Qt documentation has tutorials showing both methods. The linked documentation shows PySide6 as support for PySide2 has been discontinued with the release of Qt6. The API for PySide2, PySide6, and PyQt5 are all very similar, so if you're migrating from either PySide2 or PyQt then the change should be relatively painless. I recommend using PySide6 as this is the Python binding officially supported by Qt.

How to run a pyqt5 application properly?

I can't get the GUI for my application to run in the manner that I need it to. My question is, given the below criteria, how do I go about setting up and running the GUI properly. The lack of good documentation that I have found is insanely frustrating (maybe I'm looking in the wrong places?).
I have a main window in a file called MainCustomerWindow.py containing a class by the same name. This is where all the code from the qt designer is. I have another class file called GUIController. The GUIController class does just that, controls the multiple GUI windows. It is in this GUIController class that I am trying to instantiate and run the MainCustomerWindow. Here is the code I have been trying.
def setup_window(self):
APP = QtWidgets.QApplication(sys.argv)
Window = MainCustomerWindow()
Window.setupUi(QtWidgets.QMainWindow)
Window.show()
sys.exit(APP.exec_())
Just as a side note, I come from JavaFX and Swing, and don't fully understand the workflow for pyqt5. So if someone could add an explanation for that as well it would be greatly appreciated.
The class generated by Qt Designer is not a widget, it is a class used to fill an existing widget, so you must create an object in the window, assuming you have used the "Main Window" template, then the widget must be QMainWindow (if it is another maybe you should use QDialog or QWidget), then you have to create another class that belongs to the design, and using the method setupUi() you must pass the widget to fill it:
def setup_window(self):
app = QtWidgets.QApplication(sys.argv)
# create window
window = QtWidgets.QMainWindow()
ui = MainCustomerWindow()
# fill window
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Although a better option is to create a new class and have it inherit from both:
class MainWindow(QtWidgets.QMainWindow, MainCustomerWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
If you want to get detailed information I recommend you read the following:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html
You can try taking the code you have there and adding it to the main statement at the end of your app's script. You can also have this statement instantiate your class where the init method contains the setupui() call. For example:
if __name__ == '__main__':
app = QWidgets.QApplication(sys.argv)
window = QMainWindow()
main_window = MainCustomerWindow()
window.show()
sys.exit(app.exec())
This code first sets up the PyQt app as an instance of QApplication. Next it instantiates an instance of QMainWindow so that PyQt knows what to display as the main app starts. In my experience, I've put setupui() in the init method of the app class. In your case, in the init method of MainCustomerWindow Finally, window.show() tells PyQt to begin rendering the main window.

How do I add StandardPixmap to a layout?

I am trying to get the built in StandardPixmaps
to display on my layout.
So far I have managed to access a standard pixmap (PyQt4.QtGui.QStyle.SP_MessageBoxWarning), but seem unable to actually add this to my layout. I have tried adding it to a QLabel using the setPixmap method, but this requires a pixmap, not a standardPixmap.
I have found this answer on SO, which led me to the standardPixmaps, but I have been unable to make any more progress from here.
PyQt4.QtGui.QStyle.SP_MessageBoxWarning is an enumeration value not a pixmap.
In order to get a pixmap from it, you could give it to the standardPixmap method of the current used style.
Example:
from PyQt4 import QtGui
if __name__ == '__main__':
app = QtGui.QApplication([])
label = QtGui.QLabel()
label.setPixmap(app.style().standardPixmap(QtGui.QStyle.SP_MessageBoxWarning))
label.show()
app.exec_()
Unfortunately, the standardPixmap method is considered obsolete now. The Qt doc advises to use the standardIcon method which returns a QIcon.
If you still want to use a QLabel to display your icon, you have to build a QPixmap from the QIcon you get. You can use one of its pixmap methods for this:
from PyQt4 import QtGui
if __name__ == '__main__':
app = QtGui.QApplication([])
label = QtGui.QLabel()
icon = app.style().standardIcon(QtGui.QStyle.SP_MessageBoxWarning)
label.setPixmap(icon.pixmap(32))
label.show()
app.exec_()

Categories