在 PyQt 中设置 `WA_TransparentForMouseEvents` 属性后,如何使 Qt window 再次收到点击?
How do I make Qt window receive clicks again after setting `WA_TransparentForMouseEvents` attribute in PyQt?
根据文档,为了取消设置属性,我需要将 False
作为第二个参数传递给小部件的 setAttribute
方法。我已经这样做了,但出于某种原因 window 对鼠标事件保持透明。
这是一个最小的可重现示例:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import Qt
class Main(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.setWindowTitle('Main')
self.state = False
self.button = QPushButton(f'Secondary window can be clicked through: {self.state}')
self.button.clicked.connect(self.button_click)
self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.setLayout(self.layout)
self.secondary = Secondary()
def button_click(self):
self.state = not self.state
self.button.setText(f'Secondary window can be clicked through: {self.state}')
self.secondary.set_click_through_state(self.state)
class Secondary(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.setWindowOpacity(0.8)
self.setWindowTitle('Secondary')
def set_click_through_state(self, state: bool):
print('Received new state:', state)
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=state)
self.hide()
if state:
self.setWindowFlags(
self.windowFlags()
| Qt.WindowType.FramelessWindowHint
| Qt.WindowType.WindowStaysOnTopHint
)
else:
self.setWindowFlags(
self.windowFlags()
& ~Qt.WindowType.FramelessWindowHint
& ~Qt.WindowType.WindowStaysOnTopHint
)
self.show()
print('Attribute is set:', self.testAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
main.secondary.show()
sys.exit(app.exec())
在 Windows 10 / Python 3.10 / PyQt6 上测试。
事实证明,为小部件设置 WA_TransparentForMouseEvents
属性也会向其添加 WindowTransparentForInput
标志。我不确定为什么,但是 取消设置属性时不会删除此标志。
只需从 window 中删除 WindowTransparentForInput
标志即可解决问题:
widget.setWindowFlags(
widget.windowFlags() & ~Qt.WindowType.WindowTransparentForInput
)
根据文档,为了取消设置属性,我需要将 False
作为第二个参数传递给小部件的 setAttribute
方法。我已经这样做了,但出于某种原因 window 对鼠标事件保持透明。
这是一个最小的可重现示例:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import Qt
class Main(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.setWindowTitle('Main')
self.state = False
self.button = QPushButton(f'Secondary window can be clicked through: {self.state}')
self.button.clicked.connect(self.button_click)
self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.setLayout(self.layout)
self.secondary = Secondary()
def button_click(self):
self.state = not self.state
self.button.setText(f'Secondary window can be clicked through: {self.state}')
self.secondary.set_click_through_state(self.state)
class Secondary(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.setWindowOpacity(0.8)
self.setWindowTitle('Secondary')
def set_click_through_state(self, state: bool):
print('Received new state:', state)
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=state)
self.hide()
if state:
self.setWindowFlags(
self.windowFlags()
| Qt.WindowType.FramelessWindowHint
| Qt.WindowType.WindowStaysOnTopHint
)
else:
self.setWindowFlags(
self.windowFlags()
& ~Qt.WindowType.FramelessWindowHint
& ~Qt.WindowType.WindowStaysOnTopHint
)
self.show()
print('Attribute is set:', self.testAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
main.show()
main.secondary.show()
sys.exit(app.exec())
在 Windows 10 / Python 3.10 / PyQt6 上测试。
事实证明,为小部件设置 WA_TransparentForMouseEvents
属性也会向其添加 WindowTransparentForInput
标志。我不确定为什么,但是 取消设置属性时不会删除此标志。
只需从 window 中删除 WindowTransparentForInput
标志即可解决问题:
widget.setWindowFlags(
widget.windowFlags() & ~Qt.WindowType.WindowTransparentForInput
)