I am making a text editor and I want to implement a confirmation before closing the program if the text from the editor has not been saved.
I wrote the close event instruction.
If I wrote a text and didn't save it, then when I try to close the window I get a message with a suggestion to save the text.
If I click Don't Save or Cancel in the dialog box that appears, then the code works fine. If I click Save, then I get an error message. error message
In addition, the code in closeEvent assumes that if the text has been changed in an open text file, then it will simply save it to an existing file, and if the file has not been previously saved, then QFileDialog will be called. But my code calls QFileDialog anyway.
Although I use the code from closeEvent for the Create and Exit button and it works well there.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from PyQt5.QtCore import QFileInfo
class Ui_MyNotepad(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super().__init__()
self.file_path = ""
def setupUi(self, MyNotepad):
MyNotepad.setObjectName("MyNotepad")
MyNotepad.resize(815, 538)
MyNotepad.setStyleSheet("QTextEdit {\n"
" background-color: white;\n"
"}\n"
"QScrollBar {\n"
" background-color: white;\n"
" height: 8;\n"
" width: 8;\n"
"}\n"
"QScrollBar:handle {\n"
" background-color: #fae0e4;\n"
"}\n"
"QScrollBar:handle:pressed {\n"
" background-color: #fbb1bd;\n"
"}\n"
"QLabel, QComboBox#bar_encoding {\n"
" background-color: #F7F5FB;\n"
" border: 1px solid silver;\n"
" padding-left: 5;\n"
"}\n"
"QComboBox#bar_encoding:drop-down \n"
"{\n"
" width: 0px;\n"
" height: 0px;\n"
" border: 0px;\n"
"}\n"
"QComboBox#bar_encoding:hover {\n"
" background-color: #F9DBBD;\n"
"}\n"
"QMenuBar {\n"
" background-color: white;\n"
"}")
self.centralwidget = QtWidgets.QWidget(MyNotepad)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setContentsMargins(0, 1, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.work_space = QtWidgets.QTextEdit(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.work_space.sizePolicy().hasHeightForWidth())
self.work_space.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setKerning(True)
font.setStyleStrategy(QtGui.QFont.PreferDefault)
self.work_space.setFont(font)
self.work_space.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
self.work_space.setAcceptDrops(True)
self.work_space.setStatusTip("")
self.work_space.setAutoFillBackground(False)
self.work_space.setInputMethodHints(QtCore.Qt.ImhNone)
self.work_space.setFrameShape(QtWidgets.QFrame.NoFrame)
self.work_space.setFrameShadow(QtWidgets.QFrame.Plain)
self.work_space.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.work_space.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.work_space.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
self.work_space.setAutoFormatting(QtWidgets.QTextEdit.AutoNone)
self.work_space.setLineWrapMode(QtWidgets.QTextEdit.NoWrap)
self.work_space.setLineWrapColumnOrWidth(10)
self.work_space.setAcceptRichText(True)
self.work_space.setObjectName("work_space")
self.verticalLayout.addWidget(self.work_space)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.bar_zoom = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Verdana")
font.setPointSize(9)
self.bar_zoom.setFont(font)
self.bar_zoom.setStyleSheet("")
self.bar_zoom.setObjectName("bar_zoom")
self.horizontalLayout.addWidget(self.bar_zoom)
spacerItem1 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.bar_position = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Verdana")
font.setPointSize(9)
self.bar_position.setFont(font)
self.bar_position.setObjectName("bar_position")
self.horizontalLayout.addWidget(self.bar_position)
spacerItem2 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.bar_byte_code = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Verdana")
font.setPointSize(9)
self.bar_byte_code.setFont(font)
self.bar_byte_code.setFocusPolicy(QtCore.Qt.NoFocus)
self.bar_byte_code.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
self.bar_byte_code.setLayoutDirection(QtCore.Qt.LeftToRight)
self.bar_byte_code.setAutoFillBackground(False)
self.bar_byte_code.setInputMethodHints(QtCore.Qt.ImhNone)
self.bar_byte_code.setFrameShape(QtWidgets.QFrame.NoFrame)
self.bar_byte_code.setFrameShadow(QtWidgets.QFrame.Plain)
self.bar_byte_code.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
self.bar_byte_code.setObjectName("bar_byte_code")
self.horizontalLayout.addWidget(self.bar_byte_code)
self.bar_encoding = QtWidgets.QComboBox(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.bar_encoding.sizePolicy().hasHeightForWidth())
self.bar_encoding.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("Verdana")
font.setPointSize(9)
self.bar_encoding.setFont(font)
self.bar_encoding.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
self.bar_encoding.setEditable(False)
self.bar_encoding.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContentsOnFirstShow)
self.bar_encoding.setIconSize(QtCore.QSize(20, 20))
self.bar_encoding.setDuplicatesEnabled(False)
self.bar_encoding.setFrame(True)
self.bar_encoding.setObjectName("bar_encoding")
self.bar_encoding.addItem("")
self.bar_encoding.addItem("")
self.bar_encoding.addItem("")
self.bar_encoding.addItem("")
self.bar_encoding.addItem("")
self.horizontalLayout.addWidget(self.bar_encoding)
spacerItem3 = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem3)
self.horizontalLayout.setStretch(0, 850)
self.horizontalLayout.setStretch(2, 60)
self.horizontalLayout.setStretch(4, 60)
self.horizontalLayout.setStretch(6, 100)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.setStretch(0, 10000)
self.verticalLayout.setStretch(1, 1)
self.verticalLayout.setStretch(2, 250)
self.work_space.raise_()
MyNotepad.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MyNotepad)
self.menubar.setGeometry(QtCore.QRect(0, 0, 815, 26))
self.menubar.setAutoFillBackground(False)
self.menubar.setNativeMenuBar(True)
self.menubar.setObjectName("menubar")
self.file = QtWidgets.QMenu(self.menubar)
self.file.setObjectName("file")
MyNotepad.setMenuBar(self.menubar)
self.create = QtWidgets.QAction(MyNotepad)
self.create.setCheckable(False)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/white-theme/DATA/images/white theme/create.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.create.setIcon(icon)
self.create.setStatusTip("")
self.create.setWhatsThis("")
self.create.setObjectName("create")
self.save = QtWidgets.QAction(MyNotepad)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(":/white-theme/DATA/images/white theme/save.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.save.setIcon(icon3)
self.save.setObjectName("save")
self.save_as = QtWidgets.QAction(MyNotepad)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(":/white-theme/DATA/images/white theme/save-as.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.save_as.setIcon(icon4)
self.save_as.setObjectName("save_as")
self.exit = QtWidgets.QAction(MyNotepad)
self.exit.setObjectName("exit")
self.file.addAction(self.create)
self.file.addAction(self.save)
self.file.addAction(self.save_as)
self.file.addSeparator()
self.file.addSeparator()
self.file.addAction(self.exit)
self.menubar.addAction(self.file.menuAction())
self.retranslateUi(MyNotepad)
self.bar_encoding.setCurrentIndex(3)
QtCore.QMetaObject.connectSlotsByName(MyNotepad)
self.add_functions()
self.work_space.textChanged.connect(self.text_changed)
def retranslateUi(self, MyNotepad):
_translate = QtCore.QCoreApplication.translate
MyNotepad.setWindowTitle(_translate("MyNotepad", "Безымянный - MyNotepad"))
self.bar_zoom.setText(_translate("MyNotepad", "Стр1, стлб 1"))
self.bar_position.setText(_translate("MyNotepad", "100%"))
self.bar_byte_code.setText(_translate("MyNotepad", "Windows (CRLF)"))
self.bar_encoding.setItemText(0, _translate("MyNotepad", "ANSI"))
self.bar_encoding.setItemText(1, _translate("MyNotepad", "UTF-16 LE"))
self.bar_encoding.setItemText(2, _translate("MyNotepad", "UTF-16 BE"))
self.bar_encoding.setItemText(3, _translate("MyNotepad", "UTF-8"))
self.bar_encoding.setItemText(4, _translate("MyNotepad", "UTF-8 со спецификацией"))
self.file.setTitle(_translate("MyNotepad", "Файл"))
self.create.setText(_translate("MyNotepad", "Создать"))
self.create.setShortcut(_translate("MyNotepad", "Ctrl+N"))
self.save.setText(_translate("MyNotepad", "Сохранить"))
self.save.setShortcut(_translate("MyNotepad", "Ctrl+S"))
self.save_as.setText(_translate("MyNotepad", "Сохранить как..."))
self.save_as.setShortcut(_translate("MyNotepad", "Ctrl+Shift+S"))
self.exit.setText(_translate("MyNotepad", "Выход"))
def add_functions(self):
self.create.triggered.connect(self.create_new)
self.save.triggered.connect(self.save_file)
self.save_as.triggered.connect(self.save_as_file)
self.exit.triggered.connect(self.exit_program)
def text_changed(self):
if MyNotepad.windowTitle()[0] != "*":
MyNotepad.setWindowTitle("*" + MyNotepad.windowTitle())
def question_save(self):
self.file_name = MyNotepad.windowTitle().replace(" - MyNotepad", "").replace("*", "")
self.msgBox = QMessageBox()
self.msgBox.setWindowTitle("MyNotepad")
self.msgBox.setWindowFlags(QtCore.Qt.SubWindow)
self.msgBox.setText("Вы хотите сохранить измнения в файле\n"
+ f"\"{self.file_name}\"")
self.buttonSave = self.msgBox.addButton("Сохранить", QMessageBox.YesRole)
self.buttonDontSave = self.msgBox.addButton("Не сохранять", QMessageBox.NoRole)
self.buttonCancel = self.msgBox.addButton("Отменить", QMessageBox.RejectRole)
self.msgBox.setDefaultButton(self.buttonSave)
self.msgBox.exec_()
def create_new(self):
if MyNotepad.windowTitle()[0] == "*":
self.question_save()
if self.msgBox.clickedButton() == self.buttonSave:
if self.file_path == "":
self.save_as_file()
if self.file_path != "":
self.bar_encoding.setCurrentIndex(2)
self.file_path == ""
self.work_space.clear()
MyNotepad.setWindowTitle("Безымянный - MyNotepad")
elif self.file_path != "":
self.bar_encoding.setCurrentIndex(2)
self.save_file()
self.file_path == ""
self.work_space.clear()
MyNotepad.setWindowTitle("Безымянный - MyNotepad")
if MyNotepad.windowTitle()[0] != "*" or self.msgBox.clickedButton() == self.buttonDontSave:
self.bar_encoding.setCurrentIndex(2)
self.file_path = ""
self.work_space.clear()
MyNotepad.setWindowTitle("Безымянный - MyNotepad")
def save_file(self):
if self.file_path == "":
self.save_as_file()
elif self.file_path != "":
self.file = open(self.file_path, "w", encoding = self.bar_encoding.currentText())
text = self.work_space.toPlainText()
self.file.write(text)
self.file.close()
MyNotepad.setWindowTitle(QFileInfo(self.file_path).fileName() + " - MyNotepad")
def save_as_file(self):
self.file_path = QFileDialog.getSaveFileName(None, "Save as...", None,
"Текстовые файлы (*.txt);;All files (*.*)")[0]
try:
self.file = open(self.file_path, "w", encoding = self.bar_encoding.currentText())
text = self.work_space.toPlainText()
self.file.write(text)
self.file.close()
MyNotepad.setWindowTitle(QFileInfo(self.file_path).fileName() + " - MyNotepad")
except FileNotFoundError:
self.file_path == ""
def exit_program(self):
if MyNotepad.windowTitle()[0] == "*":
QtCore.QMetaObject.connectSlotsByName(self.question_save())
if self.msgBox.clickedButton() == self.buttonSave:
if self.file_path == "":
QtCore.QMetaObject.connectSlotsByName(self.save_as_file())
if self.file_path != "":
sys.exit()
elif self.file_path != "":
QtCore.QMetaObject.connectSlotsByName(self.save_file())
sys.exit()
elif self.msgBox.clickedButton() == self.buttonDontSave:
sys.exit()
elif MyNotepad.windowTitle()[0] != "*":
sys.exit()
def closeEvent(self, event:QtGui.QCloseEvent):
if MyNotepad.windowTitle()[0] == "*":
self.question_save()
if self.msgBox.clickedButton() == self.buttonSave:
if self.file_path == "":
self.save_as_file()
if self.file_path != "":
event.accept()
elif self.file_path != "":
self.save_file()
event.accept()
elif self.msgBox.clickedButton() == self.buttonDontSave:
event.accept()
elif self.msgBox.clickedButton() == self.buttonCancel:
event.ignore()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MyNotepad = Ui_MyNotepad()
ui = Ui_MyNotepad()
ui.setupUi(MyNotepad)
MyNotepad.show()
sys.exit(app.exec_())