【问题标题】:Pyqt - QMenu dynamically populated and clickedPyqt - QMenu 动态填充和点击
【发布时间】:2010-11-30 16:13:23
【问题描述】:

我需要能够知道我在动态生成的菜单系统中单击了哪些项目。我只想知道我点击了什么,即使它只是一个字符串表示。

def populateShotInfoMenus(self):
    self.menuFilms = QMenu()
    films = self.getList()

    for film in films:
        menuItem_Film = self.menuFilms.addAction(film)
        self.connect(menuItem_Film, SIGNAL('triggered()'), self.onFilmSet)
        self.menuFilms.addAction(menuItem_Film)

def onFilmRightClick(self, value):
    self.menuFilms.exec_(self.group1_inputFilm.mapToGlobal(value))

def onFilmSet(self, value):
    print 'Menu Clicked ', value

【问题讨论】:

    标签: python user-interface qt pyqt


    【解决方案1】:

    不要直接使用 onFilmSet 作为连接的接收者,而是使用 lambda 函数,以便您可以传递其他参数:

    receiver = lambda film=film: self.onFilmSet(self, film)
    self.connect(menuItem_Film, SIGNAL('triggered()'), receiver)
    

    【讨论】:

    • 正是我要找的东西,啊哈甜 lambda!
    【解决方案2】:

    我在这里找到了this 答案,用于在 PyQt5、python3 中处理此问题。我不喜欢它,准确地说是 bVal 变量,因为我不完全理解它,但花了很长时间才找到,所以我想我会在这里分享它。 bVal 从trigger 中获取布尔值并允许传递taskType。

    self.taskMenu = QtGui.QMenu("Task")
    self.tasks = self.getTasks() #FETCHES A LIST OF LIST
    self.menuTasks = QtGui.QMenu()
    
    for item in self.tasks:
       menuItem_Task = self.taskMenu.addAction(item[1]) 
       receiver = lambda: bVal, taskType=item: self.setTask(bVal, taskType)
       menuItem_Task.triggered.connect(receiver)
       self.taskMenu.addAction(menuItem_Task)
    
    def setTask(self, ignore_bVal, taskType):
       print taskType
    

    【讨论】:

    • 您不需要将bVal 传递给setTask,因此您可以摆脱那个丑陋的ignore_bVal。唯一的要求是在lambda 中插入一个初始参数,这样taskType 参数就不会被布尔值覆盖。一个更健壮(更通用)的解决方案是将bVal 替换为*args - 然后将忽略信号发送的所有可能的 值,并且保持关键字参数不变。跨度>
    • 感谢这个答案,我能够用 Python3 和 PyQt5 解决类似的问题。这个想法也可以在这里看到:github.com/muammar/mkchromecast/commit/…
    【解决方案3】:

    看看Qt的属性系统。您可以动态添加包含字符串或您想要的任何内容的属性,该属性定义了操作。然后就可以在 slot 中使用 sender() 方法来获取调用 slot 的 QObject。然后,查询您设置的属性并相应地做任何您想做的事情。

    但是,这不是最好的方法。不建议使用 sender(),因为它违反了面向对象的模块化原则。

    最好的方法是使用 QSignalMapper 类。此类将来自不同对象的信号映射到具有不同参数的同一槽。

    我没有使用过 PyQt,因此我无法为您提供确切的语法或示例,但通过一些研究应该不难找到。

    【讨论】:

    • 我同意这似乎是使用信号映射器的地方。
    【解决方案4】:

    我试图找出一个类似的问题,在查看了上面的代码之后,这对我有用。觉得把这一切都展示出来会很好。 =)

    self.taskMenu = QtGui.QMenu("Task")
    self.tasks = self.getTasks() #FETCHES A LIST OF LIST
    self.menuTasks = QtGui.QMenu()
    for item in self.tasks:
         menuItem_Task = self.taskMenu.addAction(item[1]) 
         receiver = lambda taskType=item[0]: self.setTask(taskType)
         self.connect(menuItem_Task, QtCore.SIGNAL('triggered()'), receiver)
         self.taskMenu.addAction(menuItem_Task)
    
    def setTask(self,taskType):
         print taskType
    

    【讨论】:

      【解决方案5】:

      只是一些额外的信息, 我不知道为什么,但是 lambda 函数不适用于新的 pyqt 连接语法:

      不工作的代码示例:

          self.contextTreeMenuAssignTo = QtGui.QMenu(self)
          actionAssign = contextMenu.addMenu( self.contextTreeMenuAssignTo )
          actionAssign.setText("Assign to : ")
          for user in self.whoCanBeAssignated() :
              actionAssignTo = QtGui.QAction( user[0]  ,self)
              self.contextTreeMenuAssignTo.addAction( actionAssignTo )
              actionAssignTo.triggered.connect(  lambda userID = user[1] :  self.assignAllTo( userID )  )
      

      但是如果你用旧式连接语法代替最后一行:

      self.connect(actionAssignTo, QtCore.SIGNAL('triggered()'),  lambda userID = user[1] :  self.assignAllTo( userID )  )    
      

      一切都很好。 使用新的连接语法,你只能得到循环的最后一个元素:(

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-21
      • 1970-01-01
      • 1970-01-01
      • 2012-02-03
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 2014-09-06
      相关资源
      最近更新 更多