QDialog不同位置使用不同组合键

QDialog different position using different key combinations

我有这个模拟关闭 window 调用自定义 QDialog 的片段:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QLabel
from PyQt5.QtCore import Qt

class ExitDialog(QDialog):
    """TODO"""
    def __init__(self):
        super().__init__()

        self.buttonSi = QPushButton("Yes")
        self.buttonSi.clicked.connect(self.si_clicked)

        self.buttonNo = QPushButton("No")
        self.buttonNo.clicked.connect(self.no_clicked)

        self.buttonNonUscire = QPushButton("Do not exit")
        self.buttonNonUscire.clicked.connect(self.non_uscire_clicked)

        self.text = QLabel("Do you want to save changes before exit?")
        self.text.setAlignment(Qt.AlignCenter)

        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.text)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.buttonSi)
        hbox2.addWidget(self.buttonNo)
        hbox2.addWidget(self.buttonNonUscire)

        self.layout = QVBoxLayout()
        self.layout.addLayout(hbox1)
        self.layout.addLayout(hbox2)

        self.setLayout(self.layout)

        self.value_choosed = None

    def keyPressEvent(self, event):
        if event.key == Qt.Key_Escape:
            event.ignore()

    def get_choosed_value(self):
        return self.value_choosed

    def si_clicked(self):
        self.value_choosed = 0
        self.close()

    def no_clicked(self):
        self.value_choosed = 1
        self.close()

    def non_uscire_clicked(self):
        self.value_choosed = 2
        self.close()


class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(400,300,400,200)
        vbox = QVBoxLayout()
        btn = QPushButton("Exit")
        btn.clicked.connect(self.btn_clicked)
        vbox.addWidget(btn)
        self.setLayout(vbox)

    def btn_clicked(self):
        self.close()

    def closeEvent(self, event):
        dialog = ExitDialog()
        dialog.exec_()
        choice = dialog.get_choosed_value()
        if choice == 0:
            event.accept()
        elif choice == 1:
            event.accept()
        else:
            event.ignore()

if __name__ == '__main__':
    a = QApplication(["TODO"])
    w = Window()
    w.show()
    sys.exit(a.exec_())

我注意到当我使用主 window 的 'x' 按钮或组合键 ALT+F4 激活 ExitDialog 时,它的位置关于使用 btn Exit.
我在 Ubuntu 18.04.5,window 管理员:GNOME Shell.

这怎么可能?

好吧,我实际上是通过在 __init__ 的末尾添加一个 QTimer 来解决的。

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QLabel, QDesktopWidget
from PyQt5.QtCore import Qt, QTimer


class ExitDialog(QDialog):
    """TODO"""
    def __init__(self):
        super().__init__()

        self.buttonSi = QPushButton("Yes")
        self.buttonSi.clicked.connect(self.si_clicked)

        self.buttonNo = QPushButton("No")
        self.buttonNo.clicked.connect(self.no_clicked)

        self.buttonNonUscire = QPushButton("Do not exit")
        self.buttonNonUscire.clicked.connect(self.non_uscire_clicked)

        self.text = QLabel("Do you want to save changes before exit?")
        self.text.setAlignment(Qt.AlignCenter)

        hbox1 = QHBoxLayout()
        hbox1.addWidget(self.text)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.buttonSi)
        hbox2.addWidget(self.buttonNo)
        hbox2.addWidget(self.buttonNonUscire)

        self.layout = QVBoxLayout()
        self.layout.addLayout(hbox1)
        self.layout.addLayout(hbox2)

        self.setLayout(self.layout)

        self.value_choosed = None

        self.timer = QTimer()
        self.timer.timeout.connect(self.setPos)
        self.timer.start(1)

    def setPos(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)
        self.timer.stop()

    def keyPressEvent(self, event):
        if event.key == Qt.Key_Escape:
            event.ignore()

    def get_choosed_value(self):
        return self.value_choosed

    def si_clicked(self):
        self.value_choosed = 0
        self.close()

    def no_clicked(self):
        self.value_choosed = 1
        self.close()

    def non_uscire_clicked(self):
        self.value_choosed = 2
        self.close()


class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setGeometry(400,300,400,200)
        vbox = QVBoxLayout()
        btn = QPushButton("Exit")
        btn.clicked.connect(self.btn_clicked)
        vbox.addWidget(btn)
        self.setLayout(vbox)

    def btn_clicked(self):
        self.close()

    def closeEvent(self, event):
        dialog = ExitDialog()
        dialog.exec_()
        choice = dialog.get_choosed_value()
        if choice == 0:
            event.accept()
        elif choice == 1:
            event.accept()
        else:
            event.ignore()

if __name__ == '__main__':
    a = QApplication(["TODO"])
    w = Window()
    w.show()
    sys.exit(a.exec_())

不知道有没有办法直接与系统的window管理器交互。