PyQt5 菜单栏(QMenuBar)详解
在PyQt5中,菜单栏(QMenuBar)是GUI应用程序中常用的组件,通常位于窗口顶部,用于组织应用的功能。下面详细介绍QMenuBar的使用方法和相关概念。
基本概念
- 菜单栏(QMenuBar):窗口顶部的水平条,包含多个菜单
- 菜单(QMenu):下拉式选项组,属于菜单栏的子项
- 菜单项(QAction):菜单中的具体功能项,可以触发事件
- 子菜单(QMenu):嵌套在其他菜单中的菜单
基础用法示例
下面是一个完整的示例,展示了如何创建一个包含多级菜单和各种功能的菜单栏:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QIcon, QFont, QColor
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 设置窗口基本属性
self.setWindowTitle("PyQt5 菜单栏示例")
self.setGeometry(300, 300, 800, 600)
# 创建菜单栏
self.create_menu_bar()
# 创建工具栏
self.create_tool_bar()
# 创建状态栏
self.create_status_bar()
# 创建中央部件
self.create_central_widget()
def create_menu_bar(self):
# 创建菜单栏
menu_bar = self.menuBar()
# 1. 文件菜单
file_menu = menu_bar.addMenu("文件(&F)")
# 添加新建文件动作
new_action = QAction("新建(&N)", self)
new_action.setShortcut("Ctrl+N")
new_action.setStatusTip("创建新文件")
new_action.triggered.connect(self.new_file)
file_menu.addAction(new_action)
# 添加打开文件动作
open_action = QAction("打开(&O)...", self)
open_action.setShortcut("Ctrl+O")
open_action.setStatusTip("打开现有文件")
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)
# 添加分隔线
file_menu.addSeparator()
# 添加保存动作
save_action = QAction("保存(&S)", self)
save_action.setShortcut("Ctrl+S")
save_action.setStatusTip("保存当前文件")
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)
# 添加另存为动作
save_as_action = QAction("另存为(&A)...", self)
save_as_action.setShortcut("Ctrl+Shift+S")
save_as_action.setStatusTip("将文件另存为")
save_as_action.triggered.connect(self.save_file_as)
file_menu.addAction(save_as_action)
# 添加分隔线
file_menu.addSeparator()
# 添加退出动作
exit_action = QAction("退出(&X)", self)
exit_action.setShortcut("Ctrl+Q")
exit_action.setStatusTip("退出应用程序")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
# 2. 编辑菜单
edit_menu = menu_bar.addMenu("编辑(&E)")
# 添加撤销动作
undo_action = QAction("撤销(&U)", self)
undo_action.setShortcut("Ctrl+Z")
undo_action.setStatusTip("撤销上一步操作")
edit_menu.addAction(undo_action)
# 添加重做动作
redo_action = QAction("重做(&R)", self)
redo_action.setShortcut("Ctrl+Y")
redo_action.setStatusTip("重做上一步操作")
edit_menu.addAction(redo_action)
# 添加分隔线
edit_menu.addSeparator()
# 添加剪切动作
cut_action = QAction("剪切(&T)", self)
cut_action.setShortcut("Ctrl+X")
cut_action.setStatusTip("剪切选中内容")
edit_menu.addAction(cut_action)
# 添加复制动作
copy_action = QAction("复制(&C)", self)
copy_action.setShortcut("Ctrl+C")
copy_action.setStatusTip("复制选中内容")
edit_menu.addAction(copy_action)
# 添加粘贴动作
paste_action = QAction("粘贴(&P)", self)
paste_action.setShortcut("Ctrl+V")
paste_action.setStatusTip("粘贴剪贴板内容")
edit_menu.addAction(paste_action)
# 添加分隔线
edit_menu.addSeparator()
# 添加查找动作
find_action = QAction("查找(&F)...", self)
find_action.setShortcut("Ctrl+F")
find_action.setStatusTip("查找文本")
edit_menu.addAction(find_action)
# 添加替换动作
replace_action = QAction("替换(&R)...", self)
replace_action.setShortcut("Ctrl+H")
replace_action.setStatusTip("替换文本")
edit_menu.addAction(replace_action)
# 3. 格式菜单
format_menu = menu_bar.addMenu("格式(&O)")
# 添加字体动作
font_action = QAction("字体(&F)...", self)
font_action.setStatusTip("设置文本字体")
font_action.triggered.connect(self.set_font)
format_menu.addAction(font_action)
# 添加颜色动作
color_action = QAction("颜色(&C)...", self)
color_action.setStatusTip("设置文本颜色")
color_action.triggered.connect(self.set_color)
format_menu.addAction(color_action)
# 4. 视图菜单
view_menu = menu_bar.addMenu("视图(&V)")
# 添加状态栏动作(可勾选)
self.status_bar_action = QAction("状态栏", self, checkable=True)
self.status_bar_action.setChecked(True)
self.status_bar_action.setStatusTip("显示或隐藏状态栏")
self.status_bar_action.triggered.connect(self.toggle_status_bar)
view_menu.addAction(self.status_bar_action)
# 添加工具栏动作(可勾选)
self.tool_bar_action = QAction("工具栏", self, checkable=True)
self.tool_bar_action.setChecked(True)
self.tool_bar_action.setStatusTip("显示或隐藏工具栏")
self.tool_bar_action.triggered.connect(self.toggle_tool_bar)
view_menu.addAction(self.tool_bar_action)
# 5. 帮助菜单
help_menu = menu_bar.addMenu("帮助(&H)")
# 添加关于动作
about_action = QAction("关于(&A)", self)
about_action.setStatusTip("显示关于信息")
about_action.triggered.connect(self.about)
help_menu.addAction(about_action)
# 添加帮助动作
help_action = QAction("帮助(&H)...", self)
help_action.setShortcut("F1")
help_action.setStatusTip("显示帮助文档")
help_action.triggered.connect(self.help)
help_menu.addAction(help_action)
# 6. 多级菜单示例
advanced_menu = menu_bar.addMenu("高级功能")
# 添加子菜单
network_menu = QMenu("网络功能", self)
# 向子菜单添加动作
download_action = QAction("下载文件", self)
network_menu.addAction(download_action)
upload_action = QAction("上传文件", self)
network_menu.addAction(upload_action)
# 将子菜单添加到高级菜单
advanced_menu.addMenu(network_menu)
# 添加另一个子菜单
database_menu = QMenu("数据库操作", self)
# 向子菜单添加动作
connect_action = QAction("连接数据库", self)
database_menu.addAction(connect_action)
query_action = QAction("执行查询", self)
database_menu.addAction(query_action)
# 将子菜单添加到高级菜单
advanced_menu.addMenu(database_menu)
def create_tool_bar(self):
# 创建工具栏
tool_bar = QToolBar("工具栏", self)
self.addToolBar(tool_bar)
# 设置工具栏图标大小
tool_bar.setIconSize(QSize(16, 16))
# 从菜单栏添加动作到工具栏
# 注意:这里使用了前面在菜单栏中创建的动作对象
# 因此不需要重新定义这些动作
actions_to_add = [
self.findChild(QAction, "新建(&N)"),
self.findChild(QAction, "打开(&O)..."),
self.findChild(QAction, "保存(&S)"),
self.findChild(QAction, "剪切(&T)"),
self.findChild(QAction, "复制(&C)"),
self.findChild(QAction, "粘贴(&P)")
]
for action in actions_to_add:
if action:
tool_bar.addAction(action)
# 添加分隔线
tool_bar.addSeparator()
# 添加自定义动作到工具栏
zoom_in_action = QAction("放大", self)
zoom_in_action.setIcon(QIcon.fromTheme("zoom-in"))
zoom_in_action.triggered.connect(lambda: self.statusBar().showMessage("放大视图"))
tool_bar.addAction(zoom_in_action)
zoom_out_action = QAction("缩小", self)
zoom_out_action.setIcon(QIcon.fromTheme("zoom-out"))
zoom_out_action.triggered.connect(lambda: self.statusBar().showMessage("缩小视图"))
tool_bar.addAction(zoom_out_action)
def create_status_bar(self):
# 创建状态栏
status_bar = self.statusBar()
status_bar.showMessage("就绪")
# 添加永久状态部件
self.status_label = QLabel("PyQt5 示例应用")
status_bar.addPermanentWidget(self.status_label)
def create_central_widget(self):
# 创建一个文本编辑区域作为中央部件
self.text_edit = QTextEdit()
self.setCentralWidget(self.text_edit)
# 以下是各种动作的槽函数
def new_file(self):
self.text_edit.clear()
self.statusBar().showMessage("新建文件")
def open_file(self):
file_name, _ = QFileDialog.getOpenFileName(self, "打开文件", "", "文本文件 (*.txt);;所有文件 (*)")
if file_name:
try:
with open(file_name, 'r', encoding='utf-8') as file:
self.text_edit.setPlainText(file.read())
self.statusBar().showMessage(f"已打开文件: {file_name}")
except Exception as e:
QMessageBox.critical(self, "错误", f"无法打开文件: {str(e)}")
def save_file(self):
# 简化版:实际应用中应检查文件是否已保存过
self.statusBar().showMessage("文件已保存")
def save_file_as(self):
file_name, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "文本文件 (*.txt);;所有文件 (*)")
if file_name:
try:
with open(file_name, 'w', encoding='utf-8') as file:
file.write(self.text_edit.toPlainText())
self.statusBar().showMessage(f"已保存文件: {file_name}")
except Exception as e:
QMessageBox.critical(self, "错误", f"无法保存文件: {str(e)}")
def set_font(self):
current_font = self.text_edit.font()
font, ok = QFontDialog.getFont(current_font, self, "选择字体")
if ok:
self.text_edit.setFont(font)
self.statusBar().showMessage(f"字体已设置为: {font.family()}")
def set_color(self):
current_color = self.text_edit.textColor()
color = QColorDialog.getColor(current_color, self, "选择颜色")
if color.isValid():
self.text_edit.setTextColor(color)
self.statusBar().showMessage(f"文本颜色已设置为: {color.name()}")
def toggle_status_bar(self, state):
if state:
self.statusBar().show()
else:
self.statusBar().hide()
def toggle_tool_bar(self, state):
for tool_bar in self.findChildren(QToolBar):
tool_bar.setVisible(state)
def about(self):
QMessageBox.about(self, "关于", "PyQt5 菜单栏示例应用\n版本 1.0")
def help(self):
QMessageBox.information(self, "帮助", "这是一个PyQt5菜单栏示例应用。\n使用菜单可以执行各种操作。")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
关键知识点
创建菜单栏:
menu_bar = self.menuBar() # 获取主窗口的菜单栏 file_menu = menu_bar.addMenu("文件") # 添加菜单
创建菜单项:
new_action = QAction("新建", self) # 创建动作 new_action.setShortcut("Ctrl+N") # 设置快捷键 new_action.triggered.connect(self.new_file) # 连接信号和槽 file_menu.addAction(new_action) # 将动作添加到菜单
创建子菜单:
advanced_menu = menu_bar.addMenu("高级功能") # 创建主菜单 network_menu = QMenu("网络功能", self) # 创建子菜单 download_action = QAction("下载文件", self) # 创建子菜单项 network_menu.addAction(download_action) # 将动作添加到子菜单 advanced_menu.addMenu(network_menu) # 将子菜单添加到主菜单
可勾选菜单项:
status_bar_action = QAction("状态栏", self, checkable=True) # 创建可勾选动作 status_bar_action.setChecked(True) # 设置初始状态 status_bar_action.triggered.connect(self.toggle_status_bar) # 连接槽函数
添加分隔线:
file_menu.addSeparator() # 在菜单中添加分隔线
菜单项的图标和快捷键:
action = QAction("复制", self) action.setIcon(QIcon.fromTheme("edit-copy")) # 设置图标 action.setShortcut("Ctrl+C") # 设置快捷键
状态栏交互:
self.statusBar().showMessage("就绪") # 在状态栏显示消息 status_bar.addPermanentWidget(self.status_label) # 添加永久部件
最佳实践
使用助记符:在菜单标题中使用
&
符号(如"文件(&F)"
),可通过Alt+字母快速访问菜单。合理分组:使用分隔线将相关菜单项分组,提高可用性。
状态提示:为每个菜单项设置
setStatusTip()
,在状态栏显示操作说明。避免菜单过深:菜单层级建议不超过3级,过深的菜单会降低可用性。
工具栏集成:将常用菜单项添加到工具栏,提高操作效率。
键盘快捷键:为常用操作设置快捷键,符合用户习惯(如Ctrl+C/V/X等)。
通过上述方法,你可以创建出功能完善、操作便捷的菜单栏系统,提升用户体验。
import sys
from PyQt5.QtWidgets import *
class Win(QMainWindow):
def __init__(self):
super(Win, self).__init__()
self.setGeometry(300,300,800,600)
self.setWindowTitle("use QMenuBar")
layout = QHBoxLayout()
bar = self.menuBar()
file = bar.addMenu("File")
new = file.addAction("New")
save = QAction("save" , self)
save.setShortcut("Ctrl+S")
file.addAction(save)
edit = file.addMenu("Edit")
copy = edit.addAction("copy")
post = edit.addAction("poste")
copy.triggered.connect(self.docopy)
post.triggered.connect(self.dopost)
new.triggered.connect(self.donew)
save.triggered.connect(self.dosave)
def donew(self,q):
sender = self.sender()
print(sender.text())
QMessageBox.information(self, "note", "new OK")
def docopy(self, q):
sender = self.sender()
print(sender.text())
QMessageBox.information(self, "note", "copy OK")
def dopost(self, q):
sender = self.sender()
print(sender.text())
QMessageBox.information(self, "note", "post OK")
def dosave(self, q):
sender = self.sender()
print(sender.text())
QMessageBox.information(self, "note", "save OK")
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Win()
form.show()
sys.exit(app.exec_())