PyQt5 - 覆盖鼠标光标并设置 Qwidget 透明以一起输入

Posted

技术标签:

【中文标题】PyQt5 - 覆盖鼠标光标并设置 Qwidget 透明以一起输入【英文标题】:PyQt5 - Overriding mouse cursor and setting Qwidget transparent for input together 【发布时间】:2022-01-20 22:57:33 【问题描述】:

我正在尝试使用具有以下两种行为的 QWidget 在 PyQt5 中编写一个简单的应用程序:

    覆盖鼠标光标 输入透明;这意味着它可以忽略鼠标输入并将其发送到后台小部件或操作系统 UI(即像覆盖行为)

我可以单独实现每个行为,即当我将它们组合在一起时,光标返回到它的默认状态(即我失去了覆盖它的能力)!

我想知道这在 QT 中是否可以实现?

from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    # Goal no. 1: override mouse cursor
    QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
    w = QWidget()
    w.setWindowOpacity(0.1)
    
    # Goal no.2: Make widget transparent for input
    w.setWindowFlags(w.windowFlags() 
    | QtCore.Qt.WindowTransparentForInput | QtCore.Qt.WindowStaysOnTopHint)

    w.resize(900, 900)
    w.show()
    sys.exit(app.exec_())

【问题讨论】:

如果Qt窗口对鼠标输入是透明的,那么底层窗口一定要确定鼠标光标吗?否则,就不会有真正的透明度...... 有没有办法将这两个功能结合到同一个应用程序中?我需要改变我的思维方式吗? 您似乎在问:“一个窗口可以同时是透明的和不透明的吗?”。你到底想达到什么目的? 我有一个 QT 应用程序,它将使用一个特殊的硬件来控制系统的鼠标光标......我需要为默认鼠标光标设置动画以显示一些状态/反馈......所以我想我可以通过创建一个透明小部件来利用 QT 来做到这一点,并且仍然利用那些帮助我覆盖鼠标光标的 QT 功能 我能够使用相关的系统 API 覆盖外部光标。但这是有风险的,不推荐......这就是为什么我现在试图在 QT 中实现这一点......但我认为你给了我一个好主意,即在系统光标位置旁边的小部件本身中绘制一些动画......我我不确定这是否有效,但我会调查它 【参考方案1】:

基于@ekhumoro 的伟大建议:

我找到了一种使用透明小部件并在屏幕上绘制一个跟随鼠标光标的动画形状的解决方案

步骤如下:

创建一个完全透明的小部件(即完全隐藏) 此小部件应覆盖整个屏幕;类似于截图应用 然后将此小部件配置为忽略所有鼠标输入 ⇒ 它应该允许鼠标光标与其后面的所有 UI 交互,就好像该小部件完全不存在一样(例如,用户可以点击此小部件) 然后可以在该透明小部件上绘制和移动形状/文本/动画 这些形状的坐标可以根据鼠标光标坐标确定 这种方法的唯一限制是我们不会覆盖系统光标,但我们会在它旁边显示动画,我相信它可以满足原始用例
from PySide6 import QtCore, QtWidgets, QtGui
from PySide6.QtCore import QTimer
from PySide6.QtGui import QPainter, QFont
from PySide6.QtWidgets import QApplication


class TransparentWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(TransparentWidget, self).__init__(parent)

        self.setAttribute(QtCore.Qt.WA_NoSystemBackground)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        # https://***.com/questions/52827296/pyside2-pass-mouse-events-to-system
        self.setWindowFlags(self.windowFlags()
                            # | QtCore.Qt.WindowTransparentForInput
                            | QtCore.Qt.X11BypassWindowManagerHint
                            | QtCore.Qt.WindowStaysOnTopHint
                            | QtCore.Qt.WA_MouseNoMask
                            | QtCore.Qt.WA_TranslucentBackground
                            | QtCore.Qt.FramelessWindowHint)

        self.x = 0
        self.y = 0
        self.number = 4

    def paintEvent(self, event):
        print(f"paintEvent self.x  self.y")

        if not self.number:
            return

        painter = QPainter()
        painter.begin(self)

        font = QFont()
        font.setBold(True)
        font.setPixelSize(15)
        painter.setFont(font)

        pen = QtGui.QPen()
        pen.setWidth(3)
        pen.setColor(QtCore.Qt.red)
        painter.setPen(pen)

        painter.setBrush(QtCore.Qt.white)
        painter.drawEllipse(self.x + 15, self.y + 15, 30, 30)
        pen = QtGui.QPen()
        pen.setColor(QtCore.Qt.black)
        painter.setPen(pen)

        painter.drawText(self.x + 26, self.y + 35, str(self.number))


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = TransparentWidget()
    w.showFullScreen()


    def func():
        w.x += 1
        w.y += 1
        w.update()


    timer = QTimer()
    timer.timeout.connect(func)
    timer.start(10)

    sys.exit(app.exec())

【讨论】:

以上是关于PyQt5 - 覆盖鼠标光标并设置 Qwidget 透明以一起输入的主要内容,如果未能解决你的问题,请参考以下文章

pyqt5 鼠标操作

PyQt5 QWidget不填充父

PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?

Pyqt5_QWidget

在 PyQt5 小部件中检测单击鼠标 - 缺少 mouseClickEvent 函数

PyQt5 中的 Matplotlib 十字准线光标