如何制作PyQt中的点击穿透窗口

4
我希望能够在PyQt中创建一个可以点击穿透的窗口;即点击窗口时,点击事件将被传递到窗口后面,以便您可以与后面的内容进行交互,而窗口仍然保持在顶部。我想要实现的效果示例是Ubuntu上默认出现在右上角的通知,您可以通过它进行点击穿透。
如果可能的话,我希望能够在PyQt中实现这一点;否则,我的平台是Linux,但Windows解决方案也可以接受!
提前感谢您的帮助!我已经思考和研究了一段时间,能够实现这一点将非常棒。
编辑:我正在尝试创建一个可以像追踪纸一样使用背景窗口的窗口。

1
这两个窗口(通知窗口和背后的窗口)属于同一个应用程序吗? - AlexVhr
点击穿透窗口后面的窗口可以是任何窗口,这可能会使它变得更加困难!干杯 - slyaer
2个回答

3
这里提供一个使用PyQt4在Windows上的解决方案。
您需要在前端小部件中重写eventFilter(在Windows上为winEvent),然后将事件转发到后端窗口。
我不完全确定,但可能有类似的方法可用于其他平台(例如,使用x11Event代替winEvent)。
祝好运!
from PyQt4 import QtCore, QtGui
import win32api, win32con, win32gui, win32ui

class Front(QtGui.QPushButton):
    def __init__(self,text="",whndl=None):
        super(Front,self).__init__(text)
        self.pycwnd = win32ui.CreateWindowFromHandle(whndl)

    # install an event filter for Windows' messages. Forward messages to 
    # the other HWND
    def winEvent(self,MSG):

        # forward Left button down message to the other window.  Not sure 
        # what you want to do exactly, so I'm only showing a left button click.  You could 
        if MSG.message == win32con.WM_LBUTTONDOWN or \
           MSG.message == win32con.WM_LBUTTONUP:

            print "left click in front window"
            self.pycwnd.SendMessage(MSG.message, MSG.wParam, MSG.lParam)
            return True, 0 # tells Qt to ignore the message

        return super(Front,self).winEvent(MSG)

class Back(QtGui.QPushButton):
    def __init__(self,text=""):
        super(Back,self).__init__(text)
        self.clicked.connect(self.onClick)

    def onClick(self):
        print 'back has been clicked'

def main():
    a = QtGui.QApplication([])

    back = Back("I'm in back...")
    back.setWindowTitle("I'm in back...")
    back.show()

    # Get the HWND of the window in back (You need to use the exact title of that window)
    whndl = win32gui.FindWindowEx(0, 0, None, "I'm in back...")

    # I'm just making the front button bigger so that it is obvious it is in front ...
    front = Front(text="*____________________________*",whndl=whndl)
    front.setWindowOpacity(0.8)
    front.show()    

    a.exec_()

if __name__ == "__main__":
    main()

干得好!我在Windows上试了一下,运行良好。你是我的英雄。 - slyaer
没问题 - 这是一个不错的挑战! - goran
我已经使用稍微不同的方法将其适应于x11,有机会时会发布它。 - slyaer

1
self.setAttribute(Qt.WA_TransparentForMouseEvents, True)
self.setAttribute(Qt.WA_NoChildEventsForParent, True)
        self.setWindowFlags(Qt.Window|Qt.X11BypassWindowManagerHint|Qt.WindowStaysOnTopHint|Qt.FramelessWindowHint)

self.setAttribute(Qt.WA_TranslucentBackground)

这个可行。已在Linux Mint 20.1 Cinnamon上测试过。 这意味着父元素一直阻止它WA_TransparentForMouseEvents


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接