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 t开发者_如何学Criggered, but also has a submenu. Clicking it triggers associated action, hovering it causes submenu to appear.
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_())
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 ;)
void CustomMenu::mouseReleaseEvent( QMouseEvent* event )
{
QAction* action = menuAction();
// Filter out submenus. TODO: Is there a better way to do this?
if ( action && !rect().contains( event->pos() ) ) {
QMenu* menu = action->menu();
action->setMenu( 0 );
QMenu::mouseReleaseEvent( event );
emit customTriggeredSignal();
action->setMenu( menu );
}
else {
QMenu::mouseReleaseEvent( event );
}
}
Combining both helpful answers, from j_kubik and jkerian, this mouseReleaseEvent() in the top-level menu subclassing QMenu ignores unwanted invocations of submenus.
I will report back as to whether the approach is suitable on Windows.
精彩评论