2

我遇到了一个让我发疯的问题。我想让 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 (完整代码)

编辑:谢谢大家非常有帮助的答案!不幸的是,我无法为您的帖子投票,因为我缺少声誉:/

4

3 回答 3

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)
...

希望能帮助到你。

于 2014-02-24T20:12:01.010 回答
1

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

一种最好的方法是在 QApplication 上安装一个事件过滤器(以便它接收所有子窗口小部件的鼠标移动事件),并使用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_())
于 2014-02-24T21:02:51.083 回答
1

这个要求并不完全:你不能让你看不到的东西表现得好像你能看到它。hide-when-not-in-use 策略的存在理由是菜单栏占据了很大的屏幕空间并且只在某些时候使用,所以当不使用时你想隐藏它。除了 ekhumoro 和 xndrme 提到的策略之外,我还可以想到两种策略:show-when-near 和 collapse-to-small-but-not-zero。

  1. 使用 show-when-near 时,您希望在鼠标靠近菜单“滑出”的边缘时显示菜单。这要求该“附近”区域中的任何小部件都捕获鼠标并通知窗口。这在 WPF 中很容易做到,其中事件在小部件树上逐级传播,因此基本面板(它是可隐藏菜单的父级)可以根据需要捕获和隐藏/显示。这很好用,但我对 Qt 的了解还不够,还不知道 Qt 是否有类似的鼠标事件冒泡。此外,实际上“近”区域不能被其他小部件使用,除非触发显示菜单,因此实际上“近”带仅用于查看,您将无法单击按钮或文本字段等在那个区域。你不妨使用技巧#2。
  2. 在折叠到小但不为零的方法中,您的菜单区域没有完全隐藏,您保留一个狭窄的“空白”带小部件,一旦聚焦,就会导致菜单出现;失去焦点时,导致菜单消失。因此,如果菜单的高度为 100(条形)或 300(条形)像素,则条带可能只有 20 像素宽,足以轻松悬停在上面,但不足以浪费屏幕空间。此外,这种技术向用户提供了一个明确的提示,即“那里有东西”,而不是隐藏菜单的情况(你必须知道它在那里,或者像浏览器内出现的工具栏一样偶然发现它 - pdf),不那么友好。

您应该考虑使用悬停延迟,以便菜单只有在延迟足够长(如半秒)时才可见。这可以确保您不会出现/消失的快速输入输出小部件,这可能会让用户感到烦恼,因为突然的变化会引起我们的注意并引起我们的注意。

于 2014-02-24T22:52:12.117 回答