【问题标题】:Custom Qt QMenu自定义 Qt QMenu
【发布时间】:2013-09-13 13:21:41
【问题描述】:

Qt 中有没有办法向QMenu 添加布局或小部件以创建自定义菜单?

下面的示例(左)是我所拥有的,我想通过添加非菜单小部件来瞄准类似于右侧模型的东西。如果QMenu 无法完成,是否有指南可以在任何地方产生类似的结果(也许通过让更标准的小部件充当上下文菜单)?

【问题讨论】:

    标签: qt qmenu custom-contextmenu


    【解决方案1】:

    当然有!在 Qt 中,如果有意志,就会有办法。

    您可能需要创建自己的类,该类使用QMenu 并使用成员QListWidget

    然后您需要生成布局并重载所有正确的QLayout 函数以重新计算大小。

    然后您需要使用此布局(想想QHBoxLayout)并排显示QMenuQListWidget

    这应该足以为您指明正确的方向。

    编辑:

    正如评论者指出的那样,你不能继承两个 QObject 的东西,所以我更新了 相应地回答。

    【讨论】:

    • @Mat 如果您想花几个小时为这个答案编写代码,请成为我的客人。我提供了足够的信息让 OP 开始。
    • 没有人要求您编写代码,您可以从答案中删除所有元数据。请注意问题是“Qt 中是否有办法向 Qmenu 添加布局或小部件以创建自定义菜单?”,而不是“请为我编写执行此操作的代码”。如果答案是“不,你需要自己写”,那很好,你的建议看起来不错。 (我不知道是否有其他方法,但 QWidgetAction 可能会被利用。)
    • @Mat 我明白你现在的意思了。我只是想说“是的,有办法”而不写代码。感谢您的澄清。我从答案中删除了元数据。
    • 我仍然习惯于使用“Qt 方式”做事,我已经在“自定义”的东西上浪费了几个小时才意识到有更简单的方法可以做到这一点,或者我根本不应该这样做。你的回答非常接近我最初的计划,所以至少我知道我现在正朝着正确的方向开始(也许我的头围绕着 Qt);我没有预料到对尺寸重新计算进行编码 - 这可能会使我严重脱轨。我会在我开始这件事后回来,以防我遇到任何严重的挂断。 :D
    • 在我看来,QLayout 的东西是最困难的。你需要重载几个虚函数。如果是我的钱,我不会这样做,因为这可能需要 8 到 12 个小时,而且我很懒。
    【解决方案2】:

    要自定义菜单项,您可以使用QWidgetAction 类。但是您想自定义菜单看起来像弹出小部件。因此,您可以继承 QMenu 并尝试根据您的需要改进菜单布局(QMenuQWidget)。你问的不是很清楚。

    【讨论】:

      【解决方案3】:

      我写了一个脚本,你可以试试。

      但我不是 QMenu 的子类。


      #!/usr/bin/env python
      # -*- coding: utf-8 -*-
      
      import sys
      from PySide.QtGui import *
      from PySide.QtCore import *
      
      
      class MenuItem(QWidget):
          """docstring for MenuItem"""
          def __init__(self, text='test', icon=None, parent=None):
              super(MenuItem, self).__init__(parent)
      
              hbox = QHBoxLayout(self)
              # hbox.setContentsMargins(0, 0, 0, 0)
              label = QLabel(text)
              btn = QPushButton()
              if icon:
                  btn.setIcon(icon)
      
              hbox.addWidget(label)
              hbox.addStretch()
              hbox.addWidget(btn)
              self.setMinimumWidth(parent.width())
      
      
      class MyMenu(QWidget):
          """docstring for MyMenu"""
          def __init__(self, parent=None):
              super(MyMenu, self).__init__(parent)
      
              self.main_width = 200
              self.main_height = 150
              self.close_menu = False
      
              self.parent = parent
              self.setGeometry(0, 0, 200, 150)
      
              self.initUI()
              self.setWindowFlags(Qt.Popup)
              # self.setWindowModality(Qt.WindowModal)
      
          def initUI(self):
              main_frame = QWidget(self)
              main_v_layout = QVBoxLayout(main_frame)
              main_v_layout.setContentsMargins(0, 0, 0, 0)
              item_1 = MenuItem('item 1', parent=self)
              item_2 = MenuItem('item 2', parent=self)
              item_3 = MenuItem('item 3', parent=self)
              main_v_layout.addWidget(item_1)
              main_v_layout.addWidget(item_2)
              main_v_layout.addWidget(item_3)
      
          def animationShow(self):
              self.close_menu = False
              self.start_close_menu = True
              self.show()
      
              # PyQt4.QtCore.QRect(0, 0, 400, 23)
              rect = self.parent.rect()
      
              # PyQt4.QtCore.QPoint(199, 11)
              center_pos = rect.center()
      
              # PyQt4.QtCore.QPoint(654, 465)
              global_center_pos = self.parent.mapToGlobal(center_pos)
      
              height = rect.height()
      
              show_pos = QPoint(
                  global_center_pos.x() - (self.width() / 2),
                  global_center_pos.y() + height)
              # print show_pos
      
              self.move(show_pos)
              self.inAnimation(show_pos)
      
          def inAnimation(self, show_pos=None):
              start_height = QSize(self.main_width, 0)
              end_height = QSize(self.main_width, self.main_height)
      
              size_anim = QPropertyAnimation(self, 'size')
              size_anim.setStartValue(start_height)
              size_anim.setEndValue(end_height)
              size_anim.setDuration(160)
              size_anim.setEasingCurve(QEasingCurve.OutQuad)
      
              opacity_anim = QPropertyAnimation(self, 'windowOpacity')
              opacity_anim.setStartValue(0.0)
              opacity_anim.setEndValue(1.0)
              opacity_anim.setDuration(260)
              opacity_anim.setEasingCurve(QEasingCurve.OutQuad)
      
              self.in_anim_group = QParallelAnimationGroup()
              self.in_anim_group.addAnimation(size_anim)
              self.in_anim_group.addAnimation(opacity_anim)
              self.in_anim_group.start()
      
          def outAnimation(self):
              try:
                  end_size = QSize(self.size().width(), 0)
      
                  pos_anim = QPropertyAnimation(self, 'size')
                  pos_anim.setEndValue(end_size)
                  pos_anim.setDuration(200)
                  pos_anim.setEasingCurve(QEasingCurve.InQuad)
      
                  opacity_anim = QPropertyAnimation(self, 'windowOpacity')
                  opacity_anim.setStartValue(1.0)
                  opacity_anim.setEndValue(0.0)
                  opacity_anim.setDuration(200)
                  opacity_anim.setEasingCurve(QEasingCurve.InQuad)
      
                  self.out_anim_group = QParallelAnimationGroup()
                  self.out_anim_group.addAnimation(pos_anim)
                  self.out_anim_group.addAnimation(opacity_anim)
                  self.out_anim_group.finished.connect(self.closeMenu)
                  self.out_anim_group.start()
      
              except RuntimeError as e:
                  pass
              except Exception as e:
                  print e
      
          def closeMenu(self):
              self.close_menu = True
              self.setVisible(False)
      
          def closeEvent(self, event):
              # super(MyMenu, self).closeEvent(event)
              if self.start_close_menu:
                  self.outAnimation()
                  self.start_close_menu = False
      
          def hideEvent(self, event):
              # print 'hideEvent', event
              super(MyMenu, self).hideEvent(event)
      
          def setVisible(self, visible):
              if self.close_menu:
                  visible = False
      
              elif not visible:
                  visible = True
      
              super(MyMenu, self).setVisible(visible)
      
      
      class Win(QWidget):
          """docstring for Win"""
          def __init__(self):
              super(Win, self).__init__()
      
              vbox = QVBoxLayout(self)
              btn = QPushButton('call menu')
              vbox.addWidget(btn)
      
              self.menu = MyMenu(btn)
              btn.clicked.connect(self.menu.animationShow)
      
      
      if __name__ == '__main__':
          app = QApplication(sys.argv)
          win = Win()
          win.show()
          sys.exit(app.exec_())
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多