Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. "Special Items" in QMenu
Forum Update on Monday, May 27th 2025

"Special Items" in QMenu

Scheduled Pinned Locked Moved General and Desktop
6 Posts 3 Posters 8.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    strattonbrazil
    wrote on last edited by
    #1

    Some programs like Maya and Wings3D have a menu, which includes a special link on some menu items on the right side (usually a square) that triggers a different feature. For example, Wings3D might have an item called "Cube", which makes a cube with default parameters. However, if you click on the highlightable/selectable box beside the "Cube" item, it will perform a different operation like bring up a popup box that allows more customizable features. I attached an image of the Wings3D example.

    Is this an easy way to do add these special menu items using QMenu and QAction? Can I just create a special layout for the QMenu or do I need to subclass it to get more fine-grained control? I know Maya 2011 just switched to Qt from another framework, so they must have implemented it somehow. I've looked at QWidgetAction, but it seems to be the wrong direction.

    !http://www.scbots.com/link_images/wings_menu.png(Wings3D menu with special items)!

    1 Reply Last reply
    0
    • B Offline
      B Offline
      baysmith
      wrote on last edited by
      #2

      If you only need a few items customized, QWidgetAction would probably be the way to go. If you want to use the feature extensively like Maya does, you'll need to implement a custom menu class. Unfortunately, setting a special layout doesn't work. QMenu internally uses style settings directly to layout the items.

      I know Maya 2011 uses a custom Qt which has been modified for some backward compatibility. This feature might be one of the modifications they made.

      Nokia Certified Qt Specialist.

      1 Reply Last reply
      0
      • F Offline
        F Offline
        fcrochik
        wrote on last edited by
        #3

        One untested idea: you probably could use the "image" associated with the action. I have never tried but once is part of the constructor I assume it works... Don't know if you can have it on the right side though.

        But if this is a "cross platform", and especially a phone, application you need to be careful. The N900, for example, has it is own way of dealing with menus/actions.

        Certified Specialist & Qt Ambassador <a href="http://www.crochik.com">Maemo, Meego, Symbian, Playbook, RaspberryPi, Desktop... Qt everywhere!</a>

        1 Reply Last reply
        0
        • S Offline
          S Offline
          strattonbrazil
          wrote on last edited by
          #4

          Would using a QWidgetAction just entail making a horizontal box layout and adding to single-action QMenus to the QWidgetAction? That way I may get mouseover highlighting to look natural.

          1 Reply Last reply
          0
          • B Offline
            B Offline
            baysmith
            wrote on last edited by
            #5

            [quote author="strattonbrazil" date="1291831458"]Would using a QWidgetAction just entail making a horizontal box layout and adding to single-action QMenus to the QWidgetAction? That way I may get mouseover highlighting to look natural. [/quote]

            I think that would work.

            Here is another (crazy) idea. Add widgets for just the "special link" controls to the QMenu, but position them manually using geometries obtained from QMenu::actionGeometry().

            Nokia Certified Qt Specialist.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              strattonbrazil
              wrote on last edited by
              #6

              Finally got around to implementing this using the two QMenu approach. Took awhile because a lot of the QMenu code is pretty complex and many functions aren't directly exposed in the QMenu API.

              The idea was pretty simple, but I had to go back and add a bunch of overrides for little things like when the mouse enters one of the internal QMenus and doesn't dehighlight any of the other actions (or vice versa). And it's pretty easy to connect to the main QMenu, so triggering the option box can emit the action from the outer menu just as the submenu does.

              @
              import sys
              from PyQt4.QtCore import *
              from PyQt4.QtGui import *

              class OptionBoxAction(QWidgetAction):
              class InWidgetMenu(QMenu):
              def enterEvent(self, event):
              # unhighlight neigboring actions (shouldn't this be built in?)
              #
              super(OptionBoxAction.InWidgetMenu, self).enterEvent(event)
              self.parent().parent().setActiveAction(None)

                  def leaveEvent(self, event):
                      super(OptionBoxAction.InWidgetMenu, self).leaveEvent(event)
                      self.update()
              
                  def mouseMoveEvent(self, event):
                      super(OptionBoxAction.InWidgetMenu, self).mouseMoveEvent(event)
                      self.update()
              
              class MainMenu(InWidgetMenu):
                  def paintEvent(self, event):
                      p = QPainter(self)
                      action = self.actions()[0] # should only have one action
                      rect = QRect(self.actionGeometry(action))
                      rect.setWidth(self.width()) # QActions don't automatically resize
                      opt = QStyleOptionMenuItem()
                      self.initStyleOption(opt, action)
                      self.style().drawControl(QStyle.CE_MenuItem, opt, p)
              
              class CustomMenu(InWidgetMenu):
                  def paintEvent(self, event):
                      p = QPainter(self)
                      action = self.actions()[0] # should only have one action
                      rect = QRect(self.actionGeometry(action))
              
                      opt = QStyleOptionMenuItem()
                      self.initStyleOption(opt, action)
                      opt.text = '' # only show icon
                      opt.icon = QIcon('./optionBox.png')
                      self.style().drawControl(QStyle.CE_MenuItem, opt, p, self)
              
              def __init__(self, *args, **kwargs):
                  super(OptionBoxAction, self).__init__(*args, **kwargs)
              
                  self._widget = QWidget()
                  self.setDefaultWidget(self._widget)
              
                  self._menuLeft = self.MainMenu()
                  self._menuRight = self.CustomMenu()
                  self._menuRight.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
                  self._menuRight.setMaximumWidth(30)
              
                  self._widget.setLayout(QHBoxLayout())
                  self._widget.layout().addWidget(self._menuLeft)
                  self._widget.layout().addWidget(self._menuRight)
                  self._widget.layout().setMargin(0)
                  self._widget.layout().setSpacing(0)
              
              def setMainAction(self, action):
                  self._menuLeft.clear()
                  self._menuLeft.addAction(action)
                  self.connect(action, SIGNAL('triggered(bool)'), self.mainTrigger)
              
              def getParentMenu(self):
                  return self._menuLeft.parent().parent()
              _parentMenu = property(getParentMenu)
              
              def mainTrigger(self, checked): 
                  self._parentMenu.hide()
                  self._parentMenu.emit(SIGNAL("triggered(QAction*)"), self._menuLeft.actions()[0])
              
              def setCustomAction(self, action):
                  self._menuRight.clear()
                  self._menuRight.addAction(action)
                  self.connect(action, SIGNAL('triggered(bool)'), self.customTrigger)
              
              def customTrigger(self, checked):
                  self._parentMenu.hide()
                  self._parentMenu.emit(SIGNAL("triggered(QAction*)"), self._menuRight.actions()[0])
              

              app = QApplication(sys.argv)
              window = QMainWindow()

              testMenu = QMenu("Test")

              add a submenu

              subMenu = testMenu.addMenu('Sub Menu of Options')
              subMenu.addAction('Option #1')
              subMenu.addAction('Option #2')

              add the action (with the option box)

              optionBoxAction = OptionBoxAction(testMenu)
              optionBoxAction.setMainAction(QAction('Test', testMenu))
              optionBoxAction.setCustomAction(QAction('Never render this', testMenu))

              add some other actions

              testMenu.addAction(optionBoxAction)
              testMenu.addAction('Really Long Action')
              testMenu.addAction('With checks').setCheckable(True)

              def triggerEvent(action):
              print('Event triggered: %s' % action.text())

              wire up the QMenu (should automatically connect signal in 'optionBoxAction')

              QObject.connect(testMenu, SIGNAL('triggered(QAction*)'), triggerEvent)

              window.menuBar().addMenu(testMenu)
              window.show()
              app.exec_()
              @

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved