Как отделить роль крестика от роли кнопки во всплывающем окне?

Рейтинг: 0Ответов: 2Опубликовано: 19.07.2023

У меня есть всплывающее окно:

...

popup = QMessageBox(self)
popup.setWindowTitle("Заголовок")
popup.move(400, 300)
popup.setText("Текст")

agreeButton = popup.addButton("Agree", QMessageBox.ButtonRole.YesRole)

popup.setDefaultButton(agreeButton)
popup.exec()
if popup.clickedButton() == agreeButton:
    print("Кнопка 'Agree' нажата")
...

По идее, только после нажатия на кнопку Agree
оно должно выводить Кнопка 'Agree' нажата, но почему-то оно также выводит это сообщение если нажать на крестик закрытия окна.

Возможно как-то совпадают роли, но я пробовал поставить для кнопки роли YesRole, NoRole и ApplyRole, но во всех случаях нажатие на крестик тоже провоцировало вывод текста.

Ответы

▲ 1Принят

Проблема возникает из-за того, что закрытие всплывающего окна (QMessageBox) при нажатии на крестик или клавишу Esc по умолчанию интерпретируется как нажатие кнопки "Отмена" (Cancel). В вашем коде проверка popup.clickedButton() == agreeButton будет истинной и при закрытии окна.

Чтобы решить эту проблему, вам нужно изменить стандартное поведение кнопки "Отмена" для всплывающего окна. Можно сделать это, установив флаг QMessageBox.RejectRole для кнопки "Отмена".

Вот исправленный код:

popup = QMessageBox(self)
popup.setWindowTitle("Заголовок")
popup.move(400, 300)
popup.setText("Текст")
agreeButton = popup.addButton("Agree", QMessageBox.ButtonRole.YesRole)
cancelButton = popup.addButton("Cancel", QMessageBox.ButtonRole.RejectRole)
popup.setDefaultButton(agreeButton)
popup.exec()

clickedButton = popup.clickedButton()
if clickedButton == agreeButton:
    print("Кнопка 'Agree' нажата")
elif clickedButton == cancelButton:
    print("Кнопка 'Cancel' нажата")

Теперь проверка clickedButton == agreeButton будет истинной только при нажатии кнопки "Agree", а не при закрытии окна.

▲ 0

Как вариант:

import sys
#PyQt6 from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        centerWidget = QtWidgets.QWidget()
        self.setCentralWidget(centerWidget)

        self.button = QtWidgets.QPushButton('Click me')
        self.button.clicked.connect(self._popup)

        layout = QtWidgets.QVBoxLayout(centerWidget)
        layout.addWidget(self.button, alignment=QtCore.Qt.AlignCenter | QtCore.Qt.AlignBottom)        
        
        self.popup = QtWidgets.QMessageBox(self)
        self.popup.setWindowTitle("Заголовок")
        self.popup.move(400, 300)
        self.popup.setText("Текст")
#PyQt6  agreeButton = popup.addButton("Agree", QtWidgets.QMessageBox.ButtonRole.YesRole)
        agreeButton = self.popup.addButton("Agree", QtWidgets.QMessageBox.YesRole)
        agreeButton.setCheckable(True)
        agreeButton.setAutoDefault(False)
        agreeButton.setDefault(False)
        self.popup.setFocus()
        self.popup.installEventFilter(self)
        
    def eventFilter(self, widget, event):
        if event.type() == QtCore.QEvent.KeyPress and event.key() == QtCore.Qt.Key_Escape:
            self.popup.hide()
            return True
        return QtWidgets.QMainWindow.eventFilter(self, widget, event)
        
    def _popup(self):
        self.popup.exec()
        if self.popup.clickedButton() and self.popup.clickedButton().isChecked():
            print("Кнопка 'Agree' нажата")
            self.popup.clickedButton().click()
        

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.setWindowTitle("MainWindow")
    w.resize(500, 500)
    w.show()
    sys.exit(app.exec())

введите сюда описание изображения