I'm using pyside2 and pyqt5 lib to loading my UI file.
from PySide2 import QtWidgets
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
class A(QtWidgets.QWidget):
def __init__(self, parent=None):
super(A, self).__init__(parent)
self.ui = QUiLoader().load('uiFile.ui')
def closeEvent(self, event):
event.ignore()
app = QApplication([])
mainWin = A()
mainWin.ui.show()
app.exec_()
In my thought, it will show '11111' when I clicked the X button.
However, it's not working at all.
here is the ui file
The problem is that "A" is a widget that is not displayed, it is not the window, so override closeEvent does not make sense. Instead you should use an event filter to monitor the window's events.
from PySide2.QtCore import QEvent, QObject
from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader
class Manager(QObject):
def __init__(self, ui, parent=None):
super(Manager, self).__init__(parent)
self._ui = ui
self.ui.installEventFilter(self)
#property
def ui(self):
return self._ui
def eventFilter(self, obj, event):
if obj is self.ui:
if event.type() == QEvent.Close:
event.ignore()
return True
super().eventFilter(obj, event)
def main():
app = QApplication([])
manager = Manager(QUiLoader().load("uiFile.ui"))
manager.ui.show()
app.exec_()
if __name__ == "__main__":
main()
If you want to override the closeEvent method of the QMainWindow used in the .ui then you must promote it and register it as this other answer shows.
Related
I'm currently trying to update my PySide code using PyQt5. And I have a class called "loader.py" that used to use "QUiLoader" from "PySide.QtUiTools", but as far as I know in PyQt5 this module has been changed by "uic".
So the problem here is that I changed my "QUiLoader" import from "uic" but I always get this error:
ui_loader.py", line 4, in <module> class UiLoader(uic): TypeError: module() takes at most 2 arguments (3 given)
Original Code in Pyside
Here is where I got the code for my PySide app
Code in PyQt5
ui_loader.py
from PyQt5 import uic
from PyQt5.QtCore import QMetaObject
class UiLoader(uic):
def __init__(self, base_instance):
uic.__init__(self, base_instance)
self.base_instance = base_instance
def createWidget(self, class_name, parent=None, name=''):
if parent is None and self.base_instance:
return self.base_instance
else:
# create a new widget for child widgets
widget = uic.createWidget(self, class_name, parent, name)
if self.base_instance:
setattr(self.base_instance, name, widget)
return widget
def load_ui(ui_file, base_instance=None):
loader = UiLoader(base_instance)
widget = loader.load(ui_file)
QMetaObject.connectSlotsByName(widget)
return widget
main.py
from PyQt5.QtWidgets import QMainWindow, QApplication
from ui_loader import load_ui
import sys
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
load_ui('my_interface.ui', self)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
I have also tried to used submethod of the class and refactoring all the code but it was useless.
You can actually load the ui using uic and then just inherit that ui into a class then self.setupUI()
ui_MainWindow, QtBaseClass = uic.loadUiType("main_window.ui")
class MainWindow(QMainWindow, ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
Another way as musicamante is suggesting would be like this:
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
uic.loadUi("main_window.ui", self)
I tried to disable it by using attribute QtCore.Qt.WA_TransparentForMouseEvents, also I tried to disable my frame, but ef mousePressEvent(self, event) is still working
import sys
from b import *
from PyQt5 import QtCore, QtGui, QtWidgets
class main_interface(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.ui.frame.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
def mousePressEvent(self, event):
print('pressed')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myapp = main_interface()
myapp.show()
sys.exit(app.exec_())
I am loading a QMainWindow from an .ui file - it's working fine but window events like resize won't be triggered. I can't really figure out what I am doing wrong.
This is the code:
class TestWindow(QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QUiLoader()
file = QFile(abspath("ui/mainwindow.ui"))
file.open(QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
def resizeEvent(self, event):
print "resize"
app = QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The .ui file can be found here.
It seems that you have a confusion, but for you to understand call the test method of TestWindow:
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent)
file.close()
self.window.show()
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
And if you move the small window observe that the event is triggered.
Why does that happen?: QUiLoader creates a widget based on the .ui that unlike uic.loadUi() or ui.loadUiType() of PyQt5 does not load in the main widget but creates a new widget, maybe that's a disadvantage but that's the limitations.
So depending on what you want to do there are several options:
To load the .ui with QUiLoader() it is not necessary to have TestWindow as a parent since it can be a QObject that monitors the events through an event filter.
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class Manager(QtCore.QObject):
def __init__(self, parent_widget=None, parent=None):
super(Manager, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
file.open(QtCore.QFile.ReadOnly)
self.window = loader.load(file, parent_widget)
file.close()
self.window.installEventFilter(self)
self.window.show()
self.setParent(self.window)
self.window.destroyed.connect(lambda *args: print(">>>>>>"))
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.Close and self.window is obj:
self.window.removeEventFilter(self)
elif event.type() == QtCore.QEvent.Resize and self.window is obj:
print("resize")
return super(Manager, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = Manager()
sys.exit(app.exec_())
Another option is to make the self.widow the centralwidget (the QMainWindow in the .ui will be the centralwidget of the TestWindow, so the resize will be from the TestWindow not from the .ui but as if the size of the .ui is changed, the same will happen with TestWindow):
import os
from PySide2 import QtCore, QtWidgets, QtUiTools
class TestWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TestWindow, self).__init__(parent)
loader = QtUiTools.QUiLoader()
file = QtCore.QFile(os.path.abspath("ui/mainwindow.ui"))
if file.open(QtCore.QFile.ReadOnly):
self.window = loader.load(file, parent)
file.close()
self.setCentralWidget(self.window)
self.show()
def resizeEvent(self, event):
print("resize")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
test = TestWindow()
sys.exit(app.exec_())
The previous methods only serve to notify you of the event but if you want to overwrite it is better that you use pyuic converting the .ui to .py
I'd like to be able to load a widget (QMainWindow in this case) from a .ui file, but also be able to extend the class so that I can do things like catch keyboard events.
For example, I have the following that doesn't work but shows what I'm trying to accomplish:
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.window = QUiLoader().load("mainwindow.ui", self)
self.setCentralWidget(self.window)
self.window.keyPressEvent = self.key_pressed
self.window.setEnabled(True)
def show(self):
self.window.show()
def key_pressed(self, event):
print(event)
Because I cannot extend the object loaded from QUiLoader, I attempted to hijack the keyPressEvent method in that object, and assign it to my own key_pressed method. This doesn't work, but I'm unsure how else to go about capturing keyboard events.
I know I could create MyMainWindow and set it's base class to QMainWindow, and then override the keyPressEvent method, but then I have to do all the layout in code, and I'd much rather leverage the .ui file. How do you go about doing this?
To listen to events from other widgets you must use an eventFilter. Also the initial window is never displayed so it is better to replace it with a QObject.
from PySide2 import QtCore, QtWidgets, QtUiTools
class MyApp(QtCore.QObject):
def __init__(self):
super(MyApp, self).__init__()
self.window = QtUiTools.QUiLoader().load("mainwindow.ui")
self.window.installEventFilter(self)
def show(self):
self.window.show()
def eventFilter(self, obj, event):
if obj is self.window:
if event.type() == QtCore.QEvent.KeyPress:
print(event.key())
return super(MyApp, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyApp()
w.show()
sys.exit(app.exec_())
import sys
from PySide2.QtCore import QFile
from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtUiTools import QUiLoader
class MyMainWindow(QMainWindow):
def __init__(self):
super().__init__()
loader = QUiLoader()
self.ui = loader.load("mainWindow.ui", self)
self.ui.pushButton_call_dialog.clicked.connect(self.call_dialog)
self.ui.close()
self.ui.show()
def call_dialog(self):
loader = QUiLoader()
self.dialog = loader.load("dialog.ui")
self.dialog.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyMainWindow()
window.show
sys.exit(app.exec_())
Hi everyone,
any idea why the second (dialog) window closes the entire application?
Of course, it is not a crash since i'm getting a message saying:
Process finished with exit code 0
Thanks for your help
You could handle your QDialog on a separate class, and then make them interact only, the structure might change a bit, but you can see if it's a viable answer:
import sys
from PySide2.QtWidgets import *
class MyWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = QPushButton("Dialog")
button.clicked.connect(self.open_dialog)
self.setCentralWidget(button)
def open_dialog(self):
dialog = MyDialog()
dialog.show()
dialog.exec_()
class MyDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
button = QPushButton("Close")
button.clicked.connect(self.close_dialog)
layout = QHBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
def close_dialog(self):
self.close()
if __name__ == "__main__":
app = QApplication()
m = MyWindow()
m.show()
sys.exit(app.exec_())
Just notice that you should include the setUp step on each class.
Hope it helps.
To put the dialog into a separate class didn't work for either.
Every time the Dialog.close() event was called, it closes the whole application.
What worked for me, was to use hide() instead