python - pyqt 多个对象共享上下文菜单
问题描述
所以我对 qt 相对较新,并且对 python 相当熟悉。但是,我有一个实例,我希望多个小部件(在本例中为标签)共享相同的自定义上下文菜单,但我需要访问小部件的信息。
当我在每个标签上使用setContextMenuPolicy
andcustomContextMenuRequested.connect
时,尽管使用第二个标签访问上下文菜单,但我只能获得第一个标签的信息。
以下是我正在使用的精简版:
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QLabel
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "PyQt5 Context Menu"
self.top = 200
self.left = 500
self.width = 200
self.height = 100
self.InitWindow()
def InitWindow(self):
self.setWindowIcon(QtGui.QIcon("icon.png"))
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.firstLabel = QLabel(self)
self.firstLabel.setText("Meep!")
self.firstLabel.setObjectName("firstLabel")
self.firstLabel.setStyleSheet("background-color: rgb(252, 233, 79);")
self.firstLabel.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.firstLabel.customContextMenuRequested.connect(self.customMenuEvent)
self.firstLabel.setGeometry(QtCore.QRect(0,0,50,30))
self.secondLabel = QLabel(self)
self.secondLabel.setText("Peem!")
self.secondLabel.setObjectName("secondLabel")
self.secondLabel.setStyleSheet("background-color: rgb(79,233, 252);")
self.secondLabel.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.secondLabel.customContextMenuRequested.connect(self.customMenuEvent)
self.secondLabel.setGeometry(QtCore.QRect(80,40,50,30))
print("FIRST:", self.firstLabel)
print("SECOND:", self.secondLabel)
self.show()
def customMenuEvent(self, eventPosition):
child = self.childAt(eventPosition)
print(child)
contextMenu = QMenu(self)
getText = contextMenu.addAction("Text")
getName = contextMenu.addAction("Name")
quitAct = contextMenu.addAction("Quit")
action = contextMenu.exec_(self.mapToGlobal(eventPosition))
if action == getText:
print(child.text())
if action == getName:
print(child.objectName())
if action == quitAct:
self.close()
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
解决方案
从有关customContextMenuRequested(pos)
信号的文档中:
位置 pos 是小部件接收到的上下文菜单事件的位置
这意味着您将始终收到相对于触发信号的小部件的鼠标位置。
您使用QWidget.childAt()
的是相对于父几何图形的 ,但由于提供的位置是相对于子小部件的,因此您最终会得到相对于父几何图形左上角的坐标。
如果您尝试将第一个小部件的几何形状设置在不是左上角的位置,这一点就会变得很清楚:即使您右键单击第一个小部件,您也会看到菜单不会出现在您单击的位置。如果您仔细观察,您还会看到菜单恰好出现在您单击的位置,基于父级左上角的坐标。
为了简单起见,一个简单的解决方案是将坐标从“ sender
”(这是发射接收器收到的最后一个信号的对象)映射到其父对象:
def customMenuEvent(self, eventPosition):
child = self.childAt(self.sender().mapTo(self, eventPosition))
contextMenu = QMenu(self)
getText = contextMenu.addAction("Text")
getName = contextMenu.addAction("Name")
quitAct = contextMenu.addAction("Quit")
# note that the mapToGlobal is referred to the child!
action = contextMenu.exec_(child.mapToGlobal(eventPosition))
# ...
但是请注意,这可能会导致一些不一致,尤其是在处理多线程时(因为理论上,另一个线程可能在右键单击事件和接收者实际接收到它的那一刻之间触发了另一个信号)。
有多种不同的方法可以避免这种情况,但 IT 主要取决于您将如何构建程序。
例如,您可以使用 lambda 添加一个参数,以帮助识别发送事件的来源:
self.firstLabel.customContextMenuRequested.connect(
lambda pos, child=self.firstLabel: self.customMenuEvent(pos, child))
# ...
def customMenuEvent(self, eventPosition, child):
# ...
推荐阅读
- c - Code Composer Studio:未解析的符号仍然存在
- php - 如何在没有插件的情况下从特定类别的帖子的 URL 中删除日期?
- linux - 在 Haskell 中,在检索时间的同时同步硬件时钟会导致严重的问题吗?
- apache-spark - 我们有火花连续处理的监听器吗?
- docker - Spring Cloud Data Flow:在 Kubernetes 集群中运行示例应用程序“partitioned-batch-job”时出现 Docker URI 错误
- asp.net - google AuthenticationManager.GetExternalLoginInfoAsync() 总是返回 null
- java - 如何区分 RequestInterceptor 中两个/多个端点之间的标头
- android - 我们可以使用 iot 从外部设备控制我们的 Android 设备吗?
- memory - IMFMediaSession::SetTopology() 导致内存不断增长
- apache - 使用 Apache 了解 ASP.NET Core