My program has a MainWindow which contains my inventory system. I have added a Dialog window which pop-ups when I clicked "Add Item". I am able to successfully open the Dialog window but I can't seem to close it.
When the user tries to close the Dialog Window, it will display a messagebox asking if the user really wants to close the window. Currently, I'm using self.close(). It just closes the MessageBox I've made to prevent accidental exit and doesn't close the Dialog window unless you end it using the IDE or task manager.
Here's my code snippets:
Main.py
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.db = Database()
self.model = Model(self)
self.ui = MainWindow_ui()
self.ui.setupUi(self)
self.window = Ui_Dialog()
self.ui.addItem.clicked.connect(lambda : self.start_Form())
def start_Form(self):
window = QtGui.QDialog()
self.window.setupUi(window)
self.window.show()
def main():
app = QtGui.QApplication(sys.argv)
window = Main()
window.showMaximized()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
AddItem.py (contains the Dialog Window code)
def getNumber():
conn = sqlite3.connect('inventory.db')
c = conn.cursor()
c.execute('SELECT seq FROM sqlite_sequence')
itemNumber = c.fetchone()[0]
return int(itemNumber) + 1
class Ui_Dialog(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self.setupUi(self)
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(413, 382)
self.buttonBox = QtGui.QDialogButtonBox(Dialog)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Reset)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
def retranslateUi(self, Dialog):
self.itemCode.setText(str(getNumber()))
def accept(self):
row = self.mapper.currentIndex()
self.mapper.submit()
self.main.model.insertRow(row)
self.mapper.setCurrentIndex(row)
self.close()
def reject(self):
ret = QtGui.QMessageBox.question(None, 'Close request', 'Are you sure you want to quit?',
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if ret == QtGui.QMessageBox.Yes:
self.close()
else:
pass
Your accept() and reject() methods effectively create an infinite loop, because calling close() will, in turn, just call those methods again. When overriding virtual methods, you should call the base-class implementation using super:
class Ui_Dialog(QtGui.QDialog):
...
def accept(self):
...
super(Ui_Dialog, self).accept()
def reject(self):
...
if ret == QtGui.QMessageBox.Yes:
super(Ui_Dialog, self).reject()
Related
I can't figure out why the signals don't work. In PyQt5, this code worked (the difference was that instead of Signal, it was pyqtSignal).
When you click on the button, TextEdit should display the message "connecting to the device", if you replace pyside with pyqt, the code will work as it should
import sys
from PySide6.QtCore import *
from PySide6.QtWidgets import *
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(188, 267)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.pushButton = QPushButton(self.centralwidget)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(50, 140, 75, 24))
self.textEdit = QTextEdit(self.centralwidget)
self.textEdit.setObjectName(u"textEdit")
self.textEdit.setGeometry(QRect(30, 40, 104, 71))
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self, parent=None)
self.dragPos = None
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
def update_text(value, textEdit):
textEdit.setText(textEdit.toPlainText() + value)
textEdit.verticalScrollBar().setValue(textEdit.verticalScrollBar().maximum())
class account(QThread):
textUpdate = Signal(str, QTextEdit)
def __init__(self):
super().__init__(parent=None)
self.textUpdate.connect(update_text)
def run(self):
print("thread is work")
self.textUpdate.emit("Connect to device\n", ui.textEdit)
if __name__ == "__main__":
app = QApplication()
acc_instance = account()
main = MainWindow()
ui = main.ui
ui.pushButton.clicked.connect(acc_instance.start)
sys.exit(app.exec_())
P.S. I know that override run method is incorrect.
P.S.S Added a small example
Your code has several problems:
The scope of "ui" is limited, it is not a global variable so you cannot use it in the run method.
Only some data types are registered (which can only be done in C++) so that they can be sent through signals, and that is not the case with QTextEdit. A workaround is to look for a parent class of the QTextEdit that is registered as a QObject or an object.
But in this case I do not see the need to send QTextEdit but only the data and then modify the GUI to set it since that is its task.
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
#Slot(str)
def update_text(self, value):
self.ui.textEdit.setText(self.ui.textEdit.toPlainText() + value)
self.ui.textEdit.verticalScrollBar().setValue(
self.ui.textEdit.verticalScrollBar().maximum()
)
class Account(QThread):
textUpdate = Signal(str)
def run(self):
print("thread is work")
self.textUpdate.emit("Connect to device\n")
if __name__ == "__main__":
app = QApplication()
main = MainWindow()
acc_instance = Account()
acc_instance.textUpdate.connect(main.update_text)
main.ui.pushButton.clicked.connect(acc_instance.start)
main.show()
sys.exit(app.exec_())
Note: In pyqt6 your initial code doesn't work either.
If you want to send texts to several QTextEdit then it is better to create a key that associates each type of text to a QTextEdit group:
from collections import defaultdict
from functools import cached_property
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self, parent=None)
self.dragPos = None
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
self.register("device_viewer", self.ui.textEdit)
# self.register("another_key", another_textedit)
def register(self, key, textedit):
if not isinstance(textedit, QTextEdit):
raise TypeError(f"{textedit} must be a QTextEdit")
self.registry_viewers[key].append(textedit)
#cached_property
def registry_viewers(self):
return defaultdict(list)
#Slot(str, str)
def update_text(self, key, value):
for textedit in self.registry_viewers[key]:
textedit.setText(textedit.toPlainText() + value)
textedit.verticalScrollBar().setValue(
textedit.verticalScrollBar().maximum()
)
class Account(QThread):
textUpdate = Signal(str, str)
def run(self):
print("thread is work")
self.textUpdate.emit("device_viewer", "Connect to device\n")
# self.textUpdate.emit("another_key", "message")
if __name__ == "__main__":
app = QApplication()
main = MainWindow()
acc_instance = Account()
acc_instance.textUpdate.connect(main.update_text)
main.ui.pushButton.clicked.connect(acc_instance.start)
sys.exit(app.exec_())
I have Mainwindow and Messagebox. On clicking Ok on messagebox, I want to close the messagebox and hide the mainwindow. Post that I want to launch the Main window based on certain condition. But this line self.msg.exec_() or self.msg.show(), ending the program with Process finished with exit code 0. I don't want to end the Mainwindow, just want to hide it and launch it again.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
import sys
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.centralwidget = QWidget(self)
self.Close = QPushButton('Close', self)
self.Close.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
self.Close.setStyleSheet(
'QPushButton {background-color: Gray;}')
self.Close.clicked.connect(lambda: self.popup_close())
vbox = QVBoxLayout()
vbox.addWidget(self.Close)
self.centralwidget.setLayout(vbox)
self.setCentralWidget(self.centralwidget)
self.show()
def popup_close(self):
self.msg = QMessageBox()
self.msg.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.WindowTitleHint)
self.msg.setIcon(QMessageBox.Critical)
self.msg.setText("Warning.")
self.msg.setStandardButtons(QMessageBox.Ok)
if self.msg == QMessageBox.Ok:
self.msg.accept()
self.hide() #hide the main window on closing the warning popup
self.msg.show()
# self.msg.exec_()
#resp = time_api.api_calls.isSubmitted(self)
#if resp['isLocked'] == True and resp['submitted'] == True:
# Main()
class Starter():
def start(self):
app = QApplication(sys.argv)
Main()
sys.exit(app.exec_())
if __name__ == "__main__":
s = Starter()
s.start()
I programming with QT Designer a GUI and would like disable the Close Event with ESC-Key. The User has the possibility to close the Application with X on the top but not with any Keys.
The Function closeEvent(self,event) are not working.
def closeEvent(self, event):
close = QMessageBox()
close.setText("You sure?")
close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
close = close.exec()
if close == QMessageBox.Yes:
event.accept()
else:
event.ignore()
The function are on my main class: class Ui_Tool(object)
class Ui_LabelTool(object):
def setupUi(self, LabelTool):
Tool.setObjectName("Tool")
Tool.resize(650, 569)
Tool.setMinimumSize(QtCore.QSize(650, 569))
Tool.setMaximumSize(QtCore.QSize(650, 569))
Tool.setAutoFillBackground(False)
Tool.setSizeGripEnabled(False)
...
#Events for Buttons
self.SelectFolder.clicked.connect(self.setfolder)
self.SelectOutputFolder.clicked.connect(self.SetOutputFolder)
self.LoadeMeasurement.clicked.connect(self.LoadRecording)
self.StartButton.clicked.connect(self.startProcessing)
self.Next_btn.clicked.connect(self.nextOperation)
self.Prev_Btn.clicked.connect(self.prefOperation)
self.Reset_btn.clicked.connect(self.resetApp)
self.treeView.clicked.connect(self.ClickMeasurement)
self.treeWidget.clicked.connect(self.CheckTopicSelect)
self.horizontalSlider.valueChanged.connect(self.SliderValueChange)
self.horizontalSlider.sliderMoved.connect(self.dispSlider)
self.BBObject_btn.clicked.connect(self.CreateBBObj)
self.BBNoObject_btn.clicked.connect(self.CreateBBNoObj)
self.ShowAll_btn.clicked.connect(self.SaveImages)
def retranslateUi(self, LabelTool):
_translate = QtCore.QCoreApplication.translate
Tool.setWindowTitle(_translate("Tool", "Tool"))
self.LoadeMeasurement.setText(_translate("Tool", "Load Measurement"))
self.StartButton.setText(_translate("Tool", "Start "))
self.Reset_btn.setText(_translate("Tool", "Reset"))
self.Header_lbl.setText(_translate("Tool", "Test"))
...
And this is my main Function:
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Tool = QtWidgets.QDialog()
ui = Ui_Tool()
ui.setupUi(Tool)
Tool.show()
sys.exit(app.exec_())
What I do wrong?
I add the following class:
class Logic(QMainWindow, Ui_Tool):
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
def closeEvent(self, event):
answer = QtWidgets.QMessageBox.question(
self,
'Are you sure you want to quit ?',
'Task is in progress !',
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No)
if answer == QtWidgets.QMessageBox.Yes:
event.accept()
else:
event.ignore()
If the docs is reviewed:
Escape Key
If the user presses the Esc key in a dialog, QDialog::reject() will be
called. This will cause the window to close: The close event cannot be
ignored.
So there are 2 possible solutions:
Override keyPressEvent() method, when you press the escape key, call close().
Override reject() method to make the verification of the QMessageBox and according to it make its logic.
In addition to this implementation you must do it in the widget and not in the class generated by Qt Designer(1), considering the above the implementations of both solutions are:
1.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_LabelTool(object):
def setupUi(self, Tool):
Tool.setObjectName("Tool")
Tool.resize(650, 569)
Tool.setMinimumSize(QtCore.QSize(650, 569))
Tool.setMaximumSize(QtCore.QSize(650, 569))
Tool.setAutoFillBackground(False)
Tool.setSizeGripEnabled(False)
# ....
class LabelTool(QtWidgets.QDialog, Ui_LabelTool):
def __init__(self, parent=None):
super(LabelTool, self).__init__(parent)
self.setupUi(self)
def verify_by_user(self):
answer = QtWidgets.QMessageBox.question(
self,
"Are you sure you want to quit ?",
"Task is in progress !",
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No,
)
return answer == QtWidgets.QMessageBox.Yes
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.close()
else:
super(LabelTool, self).keyPressEvent(event)
def closeEvent(self, event):
if self.verify_by_user():
event.accept()
else:
event.ignore()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = LabelTool()
w.show()
sys.exit(app.exec_())
2.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_LabelTool(object):
def setupUi(self, Tool):
Tool.setObjectName("Tool")
Tool.resize(650, 569)
Tool.setMinimumSize(QtCore.QSize(650, 569))
Tool.setMaximumSize(QtCore.QSize(650, 569))
Tool.setAutoFillBackground(False)
Tool.setSizeGripEnabled(False)
# ....
class LabelTool(QtWidgets.QDialog, Ui_LabelTool):
def __init__(self, parent=None):
super(LabelTool, self).__init__(parent)
self.setupUi(self)
def verify_by_user(self):
answer = QtWidgets.QMessageBox.question(
self,
"Are you sure you want to quit ?",
"Task is in progress !",
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No,
)
return answer == QtWidgets.QMessageBox.Yes
def reject(self):
if self.verify_by_user():
super(LabelTool, self).reject()
def closeEvent(self, event):
if self.verify_by_user():
event.accept()
else:
event.ignore()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = LabelTool()
w.show()
sys.exit(app.exec_())
(1) Using the Generated Code
I am trying to close a window using PyQt and open another, but this is not happening. Someone could help me?
Here is what I am doing basically:
class App(QtGui.QMainWindow, MainWindow.Ui_MainWindow):
def __init__(self, privilegio, db):
super(self.__class__, self).__init__()
self.setupUi(self)
self.get_thread = None
self.db = db
self.privilegio = privilegio
class Login(QtGui.QMainWindow, LoginWindow.Ui_McDonalds):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.verify)
self.db = None
self.db_connection = False
self.connect_db()
def login():
app = QtGui.QApplication(sys.argv)
form_login = Login()
form_login.show()
sys.exit(app.exec_())
if __name__ == '__main__':
login()
if password == result[0][0]:
main(result[0][1], self.db)
you can connect the close event (button.clicked or some else) of the first window to window2.show
by putting before sys.exit(app.exec_())
window1.rejected.connect(window2.show)
or in your first window __init__
self.rejected.connect(window2.show)
or
self.my_button.clicked.connect(window2.show)
I have some trouble with creating window application using PyQt. For example: we have the following class for GUI:
class SampleMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
...
def hideEvent(self, event):
...
def showEvent(self, event):
...
def activate(self):
...
def closeEvent(self, event):
...
What if we want to use it just for showing results and acept user inputs, and for all control logic we have another class, which use the instance of SampleMainWindow as a field:
class Programm:
def __init__(self):
self.window = SampleMainWindow()
....
app = QtGui.QApplication(sys.argv)
prog = Programm()
prog.window.show()
app.exec_()
So, if we create the instance of Programm, the application will run well, but on close we'll get an error that python.exe process could not be completed normally. But if the instance of SampleMainWindow is not a field of class:
class Programm:
def __init__(self):
win = SampleMainWindow()
....
application close well. What's the reason?
Here are the full version of Gui class:
class SampleMainWindow(QtGui.QMainWindow):
def initTray(self):
self.icon = QtGui.QSystemTrayIcon()
self.icon.setIcon(QtGui.QIcon('Tray.png'))
self.icon.show()
self.icon.activated.connect(self.activate)
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self)
moduleglobalconstants.APP_RUNNING = True
self.initTray()
self.newSession = True
self.setGeometry(300, 300, 600, 400)
self.setWindowTitle('Eye: Recently Added Lines')
self.statusBar().showMessage('Ready')
exitAction = QtGui.QAction(QtGui.QIcon('Exit.png')
,'Exit'
,self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
self.connect(exitAction
,QtCore.SIGNAL('triggered()')
,QtCore.SLOT('close()'))
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
self.toolbar = self.addToolBar('Exit')
self.toolbar.addAction(exitAction)
self.textEdit = QtGui.QTextEdit()
self.scrollPosition = self.textEdit.textCursor()
self.textEdit.setReadOnly(True)
self.setCentralWidget(self.textEdit)
def hideEvent(self, event):
self.hidden = True
self.setWindowFlags(QtCore.Qt.ToolTip)
self.setVisible(False)
def showEvent(self, event):
self.hidden = False
self.setVisible(True)
def activate(self):
self.setWindowFlags(QtCore.Qt.Window)
self.show()
self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
self.activateWindow()
def questionDialog(self, caption = 'Message',text = "Are you sure?"):
self.activate()
msgBox = QtGui.QMessageBox(self)
msgBox.setWindowTitle("Eye")
msgBox.setText(caption);
msgBox.setInformativeText(text);
msgBox.setStandardButtons(QtGui.QMessageBox.Yes| QtGui.QMessageBox.No);
msgBox.setDefaultButton(QtGui.QMessageBox.Yes);
return msgBox.exec_()
def criticalDialog(self,app, caption = 'Eye: Critical Error',text = "Impossible to continue working!"):
self.activate()
msgBox = QtGui.QMessageBox.critical(self,caption,text)
moduleglobalconstants.APP_RUNNING = False
def closeEvent(self, event):
reply = self.questionDialog()
if reply == QtGui.QMessageBox.Yes:
moduleglobalconstants.APP_RUNNING = False
event.accept()
else:
event.ignore()
def showNewLines(self, singleLine = None, lines = None, mode='insert'):
if (mode == 'rewrite'):
self.textEdit.clear()
if lines:
for line in lines:
self.textEdit.insertPlainText(line.strip() + "\n")
elif singleLine:
self.textEdit.insertPlainText(singleLine.strip()+"\n")
This has to do with python's garbage collecting - as (almost) soon an object isn't referenced anymore it destroys it, so I guess the process doesn't terminate as long as the window wasn't garbage-collected.
You can try to add at the end del Programm.window or something like that (there's probably a better way of doing this, but I never programmed QT myself so I can't help you here)
see this:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
class MyWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.label = QLabel("Hi, I'm a window", self)
self.button = QPushButton("&Quit", self)
self.connect(self.button, SIGNAL("clicked()"), QCoreApplication.instance(), SLOT("quit()"))
lay = QVBoxLayout()
lay.addWidget(self.label)
lay.addWidget(self.button)
self.setLayout(lay)
def closeEvent(self, event):
print "Closing the app"
self.deleteLater()
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MyWindow()
mw.show()
sys.exit(app.exec_())
the solution is to implement closeEvent method