我遇到了一个让我发疯的问题。我想让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(完整代码)
编辑:谢谢大家的回答!不幸的是,我不能支持你的帖子,因为我失去了声誉:/
这比看起来更棘手。主要问题是跟踪整个窗口(包括所有子窗口小部件)上的鼠标移动,并确保菜单仅在适当时隐藏(即,不在显示菜单时隐藏)。
一种方法是在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_())
这是一项有趣的任务。
这种方法的主要问题是隐藏的小部件无法接收事件(或者至少无法接收鼠标事件)。但是您仍然可以在中央小部件上实现覆盖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)
...
希望能有所帮助。
这个要求并不完全:你不能让你看不到的东西表现得像你能看到的一样。隐藏不使用策略的存在理由是菜单栏占据了大量的屏幕空间,而且只在有时使用,所以当不使用时你想隐藏它。除了ekhumoo和xndrme提到的策略之外,我还能想到两种策略:当接近时显示,以及缩小但不为零。
- 当显示在附近时,您希望菜单在鼠标靠近菜单将"滑出"的边缘时出现。这需要"附近"区域中的任何小部件都能捕获鼠标并通知窗口。在WPF中,这很容易做到,因为事件会一直向上蔓延到小部件树,所以基本面板(是可隐藏菜单的父级)可以根据需要捕获和隐藏/显示。这很好,但我对Qt的了解还不够,不知道Qt是否也有类似的鼠标事件。此外,实际上,除了触发菜单显示外,"附近"区域不能被其他小部件使用,因此实际上"附近"带仅用于查看,您将无法单击该区域中的按钮或文本字段等。你不妨使用技巧#2
- 在缩小但不为零的方法中,您的菜单区域并没有完全隐藏,您保留了一个狭窄的"空白"带小部件,一旦聚焦,就会出现菜单;当焦点不集中时,导致菜单消失。因此,如果菜单是100(条形)或300(带状)像素高,则条带可能只有20像素宽,足以轻松悬停,但不足以浪费屏幕空间。此外,这种技术向用户提供了一个明确的提示,即"那里有东西",而不是隐藏菜单的情况(你必须知道它在那里,或者像浏览器pdf中出现的工具栏一样巧合地发现它),不那么友好
您应该考虑使用悬停延迟,这样只有当延迟足够长(比如半秒)时,菜单才会可见。这确保了你不会有快速进出的小部件出现/消失,这可能会让用户感到恼火,因为突然的变化会震撼并吸引我们的注意力。