PySide make QDialog appear in main window - python

I've created an app which has an main window and the possibility to open an dialog (question, error and so on). I'm not using QMessageBox.warning() or QMessageBox.question() and so on because I wanted to customize the dialogs a bit.
But every time I open a new Dialog, in the Windows task bar (I'm working on Windows 10) a new 'tab' is opened, which is a little bit annoying.
My code (shortened):
from PySide import QtCore, QtGui
import sys
class MessageBox:
def __init__(self, title, message):
msg = QtGui.QMessageBox()
flags = QtCore.Qt.Dialog
flags |= QtCore.Qt.CustomizeWindowHint
flags |= QtCore.Qt.WindowTitleHint
msg.setWindowFlags(flags)
msg.setWindowTitle(title)
msg.setText(message)
msg.exec_()
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.show()
MessageBox("Title", "My message here")
if __name__ == "__main__":
app = QtGui.QApplication([])
window = MainWindow()
sys.exit(app.exec_())
Note: Normally, the dialog is called from an menu or button.
Question: How can I make the dialog appear in the main window without creating a new 'task bar tab'?

The solution was quite simple: Passing an reference of QMainWindow to the constructor of QDialog will do the job, e.g:
class MessageBox(QtGui.QDialog):
def __init__(self, parent, title, message, icon="info"):
super(MessageBox, self).__init__(parent)
...
and then calling the dialog from an class that inherits from QMainWindow:
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
#connect button with function, e.g.:
mybutton.clicked.connect(self.open_dialog)
def open_dialog(self):
MessageBox(self)
Maybe this helps anyone!

If you set the parent of the QDialog to the window, it will only show as one item on the task bar. This is generally the first argument to QMessageBox.
class MessageBox:
def __init__(self, parent, title, message):
msg = QtGui.QMessageBox(parent)
Also, if you really want to create a custom dialog, you might as well just subclass from QDialog.

Related

How to trigger a click event for a push button in second window using PyQt5

I have a main dialog window as shown below
Once the OK button is clicked, second window will open as shown below
I need to trigger the click event of login button frpm the second window. Below is my code. but i doesnt trigger any method.
from .gisedify_support_dialog_login import Ui_Dialog
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'gisedify_support_dialog_base.ui'))
class GisedifySupportDialog(QtWidgets.QDialog, FORM_CLASS):
def __init__(self, parent=None):
"""Constructor."""
super(GisedifySupportDialog, self).__init__(parent)
# Set up the user interface from Designer through FORM_CLASS.
# After self.setupUi() you can access any designer object by doing
# self.<objectname>, and you can use autoconnect slots - see
# http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
# #widgets-and-dialogs-with-auto-connect
self.setupUi(self)
def open_login_dialog(self):
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.exec_()
ui.login_button.clicked.connect(self.login)
def login(self):
print('success')
class Login_Dialog(QtWidgets.QDialog,Ui_Dialog):
def __init__(self, parent=None):
super(Login_Dialog, self).__init__(parent)
QDialog.exec_() will block until the dialog is closed by the user so you would need to set up any signal-slot connections before you call Dialog.exec_(). When a dialog is closed, it returns 1 when de dialog was accepted, and 0 if not. Closing the dialog does not detroy it (unless you set a flag to do so), so you can retrieve the data that was entered after Dialog.exec_() returns.
So, instead of connecting a slot to the dialog button buttonin the main window, you could instead subclass QDialog, setup the ui using your Qt Designer files, and connect the button.clicked signal to the QDialog.accept slot. Then in the main widget you can call Dialog.exec_() as before and retrieve the information afterwards, e.g.
from PyQt5 import QtWidgets, QtCore, QtGui
class Login_Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent = None):
super().__init__(parent)
self.setupUi(self)
self.login_button.clicked.connect(self.accept)
class Widget(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
# setup ui as before
def get_login(self):
dialog = Login_Dialog(self)
if dialog.exec_():
# get activation key from dialog
# (I'm assuming here that the line edit in your dialog is assigned to dialog.line_edit)
self.activation_key = dialog.line_edit.text()
self.login()
def login(self)
print(f'The activation_key you entered is {self.activation_key}')

pyqt popup window not displaying properly

I have created two different pyqt windows, and within one of them, by pressing a button, it should bring up another smaller window. While my code does pretty much exactly what I just dais it should do, there is a problem with the way the smaller popup window is displayed.
This is my code for displaying the windows and the button functionality:
from PyQt4 import QtGui
from EnterprisePassport import Ui_StudentEnterprisePassport
from Session_tracker import Ui_Session_tracker
class StudentEnterprisePassport(Ui_StudentEnterprisePassport):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.sessionTracker_btn.clicked.connect(self.handleButton)
self.window2 = None
def handleButton(self):
if self.window2 is None:
self.window2 = Session_tracker(self)
self.window2.show()
class Session_tracker(Ui_Session_tracker):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = StudentEnterprisePassport()
window.show()
sys.exit(app.exec_())
I can still use the functions within the window, but I can't move it, or close it, and there is no title bar. Have I done something wrong within my code for the popup window to appear like this?
Edit:
Original Session tracker window: Original window
Popup session tracker window: Popup window
In order to show the other widget in it's own window, it has to be a QMainWindow or a QDialog.
One option, if you don't want to convert your existing Session_tracker to a QDialog, is to just wrap it in a QDialog
def handleButton(self):
if self.window2 is None:
self.window2 = QtGui.QDialog(self)
lay = QtGui.QVBoxLayout()
self.window2.setLayout(lay)
self.session_tracker = Session_tracker(self.window2)
lay.addWidget(self.session_tracker)
self.window2.show()

How to accept close event of MainWindow when loading it with QUiLoader()?

How to receive close event in following code?
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.view = QUiLoader().load("sample.ui", self)
self.view.show()
def closeEvent(self, e):
print "close event recieved"
def main():
app = QApplication(sys.argv)
a=Main()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
If I convert sample.ui to sample.py using pyside-uic and importing this into main.py then I was able to receive close event.
from sample import Ui_MainWindow
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
def closeEvent(self, e):
print "close event recieved"
app = QApplication(sys.argv)
a=Main()
a.show()
sys.exit(app.exec_())
The second example works because it effectively becomes a subclass of the top-level class from Qt Designer. By contrast, the first example uses composition rather than subclassing, which puts all the gui elements inside an internal namespace. The Main class is just a container that acts as the parent of the view widget, and is never actually shown (which in turn means it doesn't receive any close events).
In PyQt, the uic module has several funtions which allow you to work around these issues, but there is currently nothing like that in PySide. Instead, you have to roll your own function. See this answer for an explanation of how to do that.
Alternatively, you could change the top-level class in Qt Designer to a QWidget, and then make view the central widget of your Main class. This is a lot less flexible than the above method, though.

closing PyQt Dialog terminates parent process? (PyQt4 / Pyside) with example code

I have an issue with a QSystemTrayIcon application I'm working on.
Any dialog box that I make with the SystemTrayIcon as parent or grandparent will terminate the entire application when closed, even when I override the "reject" method.
Here is a simplified example with no icon. When you run it (Windows 7 here) you should have a blank tray icon application on the task bar. If you left click it, an empty Dialog box will pop up. Clicking the "X" to close the dialog will also completely terminate the python process.
from PySide import QtGui, QtCore
class RestartDialog(QtGui.QDialog):
def __init__(self, parent):
super(RestartDialog, self).__init__()
def reject(self):
self.hide()
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, parent=None):
QtGui.QSystemTrayIcon.__init__(self, parent)
self.activated.connect(self.click_trap)
def click_trap(self, value):
''' Left click tray function '''
if value == self.Trigger: #left click!
self.dialog = RestartDialog(self)
self.dialog.show()
def show(self):
QtGui.QSystemTrayIcon.show(self)
if __name__ == "__main__":
proc = QtGui.QApplication([])
APP = SystemTrayIcon()
APP.show()
proc.exec_()
Try adding this after creating your QApplication:
proc.setQuitOnLastWindowClosed(False)
It is true by default, so your eventloop will terminate after you close the dialog.

Python crash when closing qmainwindow with qdialog open

I have a QMainWindow that launches a QDialog everytime I click on a button and I can't figure out why the python binary crashes when I close the QMainWindow while one or more dialogs are open.
It's not a complex Qt app and I'm really struggling trying to understand what happens.
Here's the code:
# dependency modules
from PyQt4 import QtGui
import sys
# custom modules
from ui import SingleOrderUI, DashBoardUI
class SingleOrder(QtGui.QDialog, SingleOrderUI.Ui_SingleOrder):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
class DashBoard(QtGui.QMainWindow, DashBoardUI.Ui_DashBoard):
def __init__(self):
QtGui.QMainWindow.__init__(self)
super(DashBoard, self).__init__()
# setup UI
self.setupUi(self)
self.newOrderBtn.clicked.connect(self.newOrder)
def newOrder(self):
print 'New order clicked'
so = SingleOrder(self)
so.show()
app = QtGui.QApplication(sys.argv)
window = DashBoard()
window.show()
sys.exit(app.exec_())
Any help would be appreciated.
EDIT: When launched using ipython, the dialogs are still showing after I close the QMainWindow, so that's maybe where the issue comes from.
I give the QMainWindow as a parent argument to the QDialog, I thought that was enough to have them killed when the QMainWindow is closed.
Okay, I've found a workaround for that but I'm not sure if it's the right way to do it.
On my DashBoard init method, I've added a python list that will store all the opened Dialogs:
def __init__(self):
QtGui.QMainWindow.__init__(self)
super(DashBoard, self).__init__()
# setup UI
self.setupUi(self)
self.newOrderBtn.clicked.connect(self.newOrder)
self.soTab = []
Then, in the same class, I defined a method to handle the closeEvent and close all the dialogs.
def closeEvent(self, event):
for so in self.soTab:
if so:
so.close()
event.accept()

Categories

Resources