在主窗口位于 python 和 pyqt5 的同一监视器上打开弹出通知

Open popup notification on the same monitor where the mainwindow is in python an pyqt5

在我的 QMainWindow 中,我有一个按钮,当我单击它时,它会在右下角的监视器角打开一个新的 QDialog,并显示一条成功消息。 现在,如果我将 QMainWindow 移动到另一个监视器(我有 3 个监视器)并单击按钮,成功消息弹出窗口将出现在 QMainWindow 打开的监视器中。我想要的是弹出消息出现在我的 QMainWindow 实际所在的监视器中。因此,如果我将 QMainWindow 移动到监视器 1 并单击按钮,successpopup 应该在监视器 1 中打开。如果 QMainWindow 在监视器 2 中,successpopup 应该在监视器 2 中打开,与监视器 3 相同.

screenNumber = QDesktopWidget().screenNumber(self)

我可以读取主窗口所在的屏幕编号。这很好用。每次我单击按钮时,我都会读出屏幕编号。但我没有找到一种方法,将屏幕编号设置为我的通知。 有什么想法吗?

编辑: 如果我显示我的通知 class

可能会有帮助

notes.py

from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"

class notify(QDialog, Ui_Notification):
    def __init__(self, parent=None):
        super(notify,self).__init__(parent)
        self.setupUi(self)
        self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
        ## Some helping stuff
        ############################################################
        parent_sSize = QDesktopWidget().screenGeometry(parent)
        parent_screenNumber = QDesktopWidget().screenNumber(parent)
        sSize = QDesktopWidget().screenGeometry()
        screenNumber = QDesktopWidget().screenNumber()
        print("notification ScreenNumber = " + str(screenNumber))
        print(sSize.width())
        print(sSize.height())
        print("Parents ScreenNumber = " + str(parent_screenNumber))
        print(parent_sSize.width())
        print(parent_sSize.height())
        self.Note_Exit.clicked.connect(self.close)
        ## ScreenSize from parent
        ############################################################
        self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
                              parent_sSize.height()-self.height()+200,
                              self.frameGeometry().width(),
                              self.frameGeometry().height())
        self.showPos = QRect(parent_sSize.width()-self.width()-10,
                              parent_sSize.height()-self.height()-50,
                              self.frameGeometry().width(),
                              self.frameGeometry().height())
    
    def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
        self.icon = icon
        self.headline = headline
        self.text = text
        self.noty_Label_Icon.setText(self.icon)
        self.noty_Label_Headline.setText(self.headline)
        self.noty_Label_Text.setText(self.text)
        self.setGeometry(self.hidedPos)
        self.anim = QPropertyAnimation(self,b"geometry")
        self.anim.setDuration(700)
        self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
        self.anim.setEndValue(self.showPos)
        self.anim.start()
        self.notyTimer = QTimer()
        self.notyTimer.singleShot(4000,self.hideNote)
    def hideNote(self):
        self.anim = QPropertyAnimation(self,b"geometry")
        self.anim.setDuration(700)
        self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
        self.anim.setEndValue(self.hidedPos)
        self.anim.start()
        self.anim.finished.connect(self.close)

if __name__ == "__main__":     
    notes = QApplication(sys.argv)
    dialog = notify()
    dialog.show()
    sys.exit(notes.exec())

您不能在构造期间使用小部件的大小,因为此时它具有默认大小(顶级小部件为 640x480,由父级创建的小部件为 100x30,包括对话框):唯一可靠的选择是使用 sizeHint() 或确保已使用 adjustSize().

正确激活布局

然后,您不需要屏幕来获取目标位置,因为父几何体就足够了,但是您确实需要它作为起始位置,否则对话框将在window下方的任意点“弹出”。请注意,QDesktopWidget 被认为已过时,您应该改用 QScreen。

最后,由于您可能想重复使用通知,因此应在实际显示弹出窗口时设置开始位置,而不是之前。隐藏时的位置也是如此(以防通知可以移动)。

class Notify(QDialog, Ui_Notification):
    def __init__(self, parent):
        super().__init__(parent)
        self.setupUi(self)
        self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        self.showAnim = QPropertyAnimation(self, b'geometry')
        self.showAnim.setDuration(700)
        self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)

        self.hideAnim = QPropertyAnimation(self, b'geometry')
        self.hideAnim.setDuration(700)
        self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)

        self.hideTimer = QTimer(self, singleShot=True)
        self.hideTimer.setInterval(4000)

        self.hideTimer.timeout.connect(self.hideNote)
        self.showAnim.finished.connect(self.hideTimer.start)
        self.hideAnim.finished.connect(self.close)

    def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
        self.icon = icon
        self.headline = headline
        self.text = text
        self.noty_Label_Icon.setText(self.icon)
        self.noty_Label_Headline.setText(self.headline)
        self.noty_Label_Text.setText(self.text)

        self.adjustSize() # important!
        endRect = self.rect()
        center = self.parent().geometry().center()
        endRect.moveCenter(center)
        screen = QApplication.screenAt(center)
        startRect = QRect(endRect)
        startRect.moveTop(screen.geometry().bottom())

        self.setGeometry(startRect)
        self.showAnim.setStartValue(startRect)
        self.showAnim.setEndValue(endRect)
        self.showAnim.start()
        self.show()

    def hideNote(self):
        rect = self.geometry()
        self.hideAnim.setStartValue(rect)
        screen = QApplication.screenAt(rect.center())
        rect.moveTop(screen.geometry().bottom())
        self.hideAnim.setEndValue(rect)
        self.hideAnim.start()


if __name__ == "__main__":     
    notes = QApplication(sys.argv)
    notes.setStyle('fusion')
    w = QMainWindow()
    b = QPushButton('click!')
    w.setCentralWidget(b)
    w.show()
    notify = Notify(w)
    b.clicked.connect(lambda: notify.setNote())
    sys.exit(notes.exec())

请注意,如果每次都创建弹出窗口,还应设置 WA_DeleteOnClose 属性以便在关闭时销毁它,否则它会保留在内存中。

注意:QTimer.singleShot() 是一个静态函数,创建一个 QTimer 实例来使用它是没有意义的,因为该实例不会被使用并且 new QTimer 无论如何都会被创建。

谢谢。 与此同时,我找到了一个适合我的解决方案。 看起来有点脏,但有效。 你能告诉我,我的代码和你的有什么区别吗? 我为什么要使用你的代码,除非你是一个更好的程序员 ;-) 我设置了 WA_DeleteOnClose 属性。 很高兴知道。谢谢

notes.py

from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
    checked = "check-circle"
    alert = "times-circle"
    question = "question-circle"
    clock = "clock"

class notify(QDialog, Ui_Notification):
    def __init__(self, parent=None):
        super(notify,self).__init__(parent)
        self.setupUi(self)
        self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
        self.setWindowModality(QtCore.Qt.NonModal)
        self.Note_Exit.clicked.connect(self.close)
        self.parent_h = self.parent().geometry().height()
        self.parent_w = self.parent().geometry().width()
        self.parent_x = self.parent().geometry().x()
        self.parent_y = self.parent().geometry().y()
        self.dialog_w = self.width()
        self.dialog_h = self.height()   
        self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
        ## ScreenSize from parent
        ############################################################
    
    def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
        self.icon = icon
        self.headline = headline
        self.text = text
        self.noty_Label_Icon.setText(self.icon)
        self.noty_Label_Headline.setText(self.headline)
        self.noty_Label_Text.setText(self.text)
        self.anim = QPropertyAnimation(self,b"geometry")
        self.anim.setDuration(700)
        self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
        self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
        self.anim.start()
        self.notyTimer = QTimer()
        self.notyTimer.singleShot(4000,self.hideNote)
    def hideNote(self):
        self.anim = QPropertyAnimation(self,b"geometry")
        self.anim.setDuration(700)
        self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
        self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
        self.anim.start()
        self.anim.finished.connect(self.close)

if __name__ == "__main__":     
    notes = QApplication(sys.argv)
    dialog = notify()
    dialog.show()
    sys.exit(notes.exec())