tags:

views:

55

answers:

2

Hello,

I am writing in Qt 4.6. I am wondering if it's possible to achieve such a menu item, that it's possible to be triggered, but also has a submenu. Clicking it triggers associated action, hovering it causes submenu to appear.

+1  A: 

Let me start by saying that this is not a good plan of attack. There are corner cases here that will take a rediculous amount of time and code to get just right, and will probably require per-operating system customization.

With that said, however, the actual implementation isn't too complicated. Just subclass the QMenu that you're making your submenu from, and override the event handlers, forcing the parent menu closed when a 'selection' is made. Something like the following basically works:

from PyQt4 import QtCore, QtGui
import sys

app = QtGui.QApplication(sys.argv)
widget = QtGui.QMainWindow()
widget.resize(250,150)
menu = widget.menuBar().addMenu("test")

class submenu(QtGui.QMenu):                   #Override the submenu class
    def __init__(self,name):
        QtGui.QMenu.__init__(self,name)
    def mouseReleaseEvent(self,event):    #catch mouseRelease Events
        global menu
        QtGui.QMenu.mouseReleaseEvent(self,event)
        if not self.rect().contains(event.pos()):
            print("Parent Selected")
            menu.hide()                  #If the parent was selected, hide it
        else:                            #Likely ignore these
            print("Parent NOT Selected")

def c():
    print("Sub-item selected")
cMenu = submenu("Sub-menu")
menu.addMenu(cMenu)
actionC = QtGui.QAction("sub-item",widget)
actionC.triggered.connect(c)
cMenu.addAction(actionC)

widget.show()

sys.exit(app.exec_())
jkerian
A: 

This behavior is a bit confusing, but i am trying to develop a UI with as little clicking as possible. Although a bit unexpected, this behavior makes it a bit faster to use when you get used to it.

I haven't wrote that in my previous message, but i am writing in c++, and i have no idea about python... Anyway i managed to translate idea to c++, and it works but it's quite ugly... I found a bit better approach by looking through qt source (when i was asking this question I was hoping there is some better, "intended" method)

class MyMenu : public QMenu
{
Q_OBJECT
public:
    MyMenu(QWidget* parent);

    ~MyMenu();

    virtual void mouseReleaseEvent( QMouseEvent * event );

};

MyMenu::MyMenu(QWidget* parent):QMenu(parent)
{
}

MyMenu::~MyMenu()
{
}

void MyMenu::mouseReleaseEvent( QMouseEvent * event ){
  QAction* act = menuAction();
  if (act){
    QMenu* men = act->menu();
    act->setMenu(0);

    QMenu::mouseReleaseEvent(event);
    act->setMenu(men);
  }else{
    QMenu::mouseReleaseEvent(event);
  }
}

The only disadvantage is that such a menu would react to clicking on all options with submenus, not only desired ones. Perhaps it would be a good idea to check if anything is connected to action's signals?

On my ubuntu it works. However i guess it wouldn't work on windows, where system manages menus exclusively (unless qt uses some windows with menu's look and feel, not system menus), but i am too lazy to instal windows just to check it ;)