PyQT4 QMenuBar Visibilty由MouseOver切换

时间:2014-02-24 17:28:28

标签: python qt pyqt mouseover qmenubar

我遇到了一个让我疯狂的问题。 我想让QMenuBar只在被鼠标悬停时可见,否则它应该被隐藏。

到目前为止,我得到了“工作”:

class Hidden_Menubar(QtGui.QMenuBar):           
    def __init__(self, parent=None):
        super(Hidden_Menubar, self).__init__(parent)        
        self.setMouseTracking(True)                     

    def enterEvent(self,event):       
        self.show()

    def leaveEvent(self,event):
        self.hide()

 class Ui_Template_FullScreen(object):
        def setupUi(self, Template_FullScreen):
            Template_FullScreen.setObjectName(_fromUtf8("Template_FullScreen"))
            Template_FullScreen.showFullScreen()        
            self.centralwidget = QtGui.QWidget(Template_FullScreen)
            self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
            Template_FullScreen.setCentralWidget(self.centralwidget)

            self.menubar = Hidden_Menubar(Template_FullScreen)
            ......

问题是,只要鼠标停止盘旋QMenuBar,它就会消失(到目前为止一直很好),但如果我再次悬停QMenuBar区域则不会显示! 我想mouseMoveEvent不会触发隐藏的对象,或者是其他什么问题?我尝试了很多解决方案,例如安装事件过滤器,但是我无法正确实现它。 我对python和QT完全不熟悉,所以我自己也搞清楚了。 我感谢你的每一个帮助。

提前致谢=)

test.py: http://pastebin.com/hmRvYVup(完整代码)

编辑:谢谢大家的帮助!不幸的是我不能赞成你的帖子,因为我缺少声望:/

3 个答案:

答案 0 :(得分:1)

这是一项有趣的任务。

您的方法的主要问题是隐藏的小部件不会接收事件(或至少是鼠标事件)。但是你仍然可以在中央窗口小部件上实现覆盖mouseMoveEvent的行为,试试这个:

class Hidden_Menubar(QtGui.QMenuBar):

    def __init__(self, parent=None, centralWidget=None):
        super(Hidden_Menubar, self).__init__(parent)  
        if centralWidget:
            centralWidget.setMouseTracking(True)   
            centralWidget.mouseMoveEvent = self.onMove

    def onMove(self, evt): 
        if self.isVisible():
            self.hide()
        elif evt.pos().y()<20:
            self.show()

当然,您的Hidden_Menubar应该以这种方式实例化:

...
self.menubar = Hidden_Menubar(Template_FullScreen,self.centralwidget)
...

希望它有所帮助。

答案 1 :(得分:1)

这比它看起来更棘手。主要问题是在整个窗口(包括所有子窗口小部件)上跟踪鼠标移动,并确保仅在适当时隐藏菜单(即,不显示菜单时)。

这样做的一种方法是在QApplication上安装event-filter(以便它接收所有子窗口小部件的鼠标移动事件),并使用activePopupWidget方法检查是否存在是任何活跃的菜单。

这是一个演示脚本,显示了一个基本实现:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        # add a few widgets for testing
        widget = QtGui.QWidget(self)
        edit = QtGui.QTextEdit(widget)
        button = QtGui.QPushButton('Button', widget)
        layout = QtGui.QVBoxLayout(widget)
        layout.addWidget(edit)
        layout.addWidget(button)
        self.setCentralWidget(widget)
        menu = self.menuBar().addMenu('&File')
        menu.addAction('&Quit', self.close)
        menu = self.menuBar().addMenu('&Edit')
        menu.addAction('&Clear', edit.clear)
        QtGui.qApp.installEventFilter(self)
        # make sure initial window size includes menubar
        QtCore.QTimer.singleShot(0, self.menuBar().hide)

    def eventFilter(self, source, event):
        # do not hide menubar when menu shown
        if QtGui.qApp.activePopupWidget() is None:
            if event.type() == QtCore.QEvent.MouseMove:
                if self.menuBar().isHidden():
                    rect = self.geometry()
                    # set mouse-sensitive zone
                    rect.setHeight(25)
                    if rect.contains(event.globalPos()):
                        self.menuBar().show()
                else:
                    rect = QtCore.QRect(
                        self.menuBar().mapToGlobal(QtCore.QPoint(0, 0)),
                        self.menuBar().size())
                    if not rect.contains(event.globalPos()):
                        self.menuBar().hide()
            elif event.type() == QtCore.QEvent.Leave and source is self:
                self.menuBar().hide()
        return QtGui.QMainWindow.eventFilter(self, source, event)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 300, 100)
    window.show()
    sys.exit(app.exec_())

答案 2 :(得分:1)

要求并不是真正完整的:你不能拥有一些你看不到的东西就好像你能看到它一样。隐藏时不使用策略的存在理由是菜单栏占用了大量屏幕空间并且仅在有时使用,因此在不使用时您想要隐藏它。我可以想到除了ekhumoro和xndrme提到的两种策略之外的两种策略:show-when-near,以及collapse-to-small-but-not-zero。

  1. 当显示在附近时,您希望当鼠标靠近菜单将“滑出”的边缘时显示菜单。这要求在“近”区域中的任何小部件捕获鼠标并通知窗口。这在WPF中很容易做到,其中事件在窗口小部件树中涓涓细流,因此基本面板(可隐藏菜单的父级)可以根据需要捕获和隐藏/显示。这很好用,但我还不知道Qt还不知道Qt是否有类似的鼠标事件冒泡。此外,实际上除了触发菜单显示之外,其他小部件不能使用“近”区域,因此实际上“近”带仅对查看有用,您将无法单击按钮或文本字段等在那个地区。你不妨使用技巧#2。
  2. 在折叠到小而非零的方法中,您的菜单区域并未完全隐藏,您保留一个狭窄的“空白”乐队小部件,一旦聚焦,就会出现菜单;当焦点松散时,会导致菜单消失。因此,如果菜单为100(条形)或300(色带)像素高,则该条带可能只有20像素宽,足以轻易地悬停,但不足以浪费屏幕空间。此外,这种技术为用户提供了一个明确的提示:“那里有东西”,而不是隐藏菜单的情况(你必须知道它在那里,或者像在浏览器中出现的工具栏一样巧妙地发现它) pdf),不那么友好。
  3. 你应该考虑使用悬停延迟,这样只有延迟足够长时间(如半秒),菜单才会变得可见。这样可以确保您没有快速进出的小部件出现/消失,这可能会让用户感到烦恼,因为突然的变化会引起我们的注意。