如何在PyQt5应用中将菜单栏添加到顶部标题栏而非窗口内部
PyQt5 菜单栏嵌入标题栏实现方案
要实现菜单栏和标题栏同屏显示,核心思路是禁用系统原生标题栏,自行实现自定义标题栏布局,将菜单栏整合进去。以下是调整后的完整可运行代码:
import sys from PyQt5.QtCore import Qt, QPoint from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import (QApplication, QLabel, QMainWindow, QMenu, QWidget, QHBoxLayout, QPushButton, QSizePolicy) class Window(QMainWindow): def __init__(self, parent=None): super().__init__(parent) # 禁用原生标题栏 self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint) self.resize(400, 200) # 记录窗口拖拽偏移量 self.drag_offset = QPoint() # 自定义标题栏区域 self.title_bar = QWidget() self.title_bar.setFixedHeight(30) # 和菜单栏高度匹配 self.title_layout = QHBoxLayout(self.title_bar) self.title_layout.setContentsMargins(8,0,8,0) self.title_layout.setSpacing(8) # 1. 窗口图标 icon_label = QLabel() icon_label.setPixmap(QIcon.fromTheme("application-x-executable").pixmap(16,16)) self.title_layout.addWidget(icon_label) # 2. 菜单栏 self.menu_bar = self.menuBar() self.menu_bar.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) self.menu_bar.addMenu(QMenu("&File", self)) self.menu_bar.addMenu("&Edit") self.menu_bar.addMenu("&Help") self.title_layout.addWidget(self.menu_bar) # 3. 窗口标题(撑满中间空间) title_label = QLabel("< Menu Go Here") title_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.title_layout.addWidget(title_label, stretch=1) # 4. 窗口控制按钮 min_btn = QPushButton("-") min_btn.setFixedSize(30,30) min_btn.clicked.connect(self.showMinimized) self.title_layout.addWidget(min_btn) max_btn = QPushButton("□") max_btn.setFixedSize(30,30) max_btn.clicked.connect(self.toggle_maximize) self.title_layout.addWidget(max_btn) close_btn = QPushButton("×") close_btn.setFixedSize(30,30) close_btn.clicked.connect(self.close) self.title_layout.addWidget(close_btn) # 把自定义标题栏设置为窗口菜单栏区域控件 self.setMenuWidget(self.title_bar) # 原有中心内容 self.centralWidget = QLabel("Hello, World") self.centralWidget.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.setCentralWidget(self.centralWidget) # 窗口拖拽功能实现 def mousePressEvent(self, event): if event.button() == Qt.LeftButton and event.y() < self.title_bar.height(): self.drag_offset = event.globalPos() - self.frameGeometry().topLeft() event.accept() def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton and event.y() < self.title_bar.height(): self.move(event.globalPos() - self.drag_offset) event.accept() # 最大化/还原切换 def toggle_maximize(self): if self.isMaximized(): self.showNormal() else: self.showMaximized() if __name__ == "__main__": app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec_())
关键修改说明
- 调用
setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)隐藏系统原生标题栏,获得完全自定义标题栏的权限 - 新建自定义标题栏控件,用水平布局依次放入窗口图标、菜单栏、窗口标题、控制按钮,实现和需求一致的布局
- 用
setMenuWidget方法把自定义标题栏设置为菜单栏区域控件,确保它显示在窗口最顶部,不会占用中心内容区域的空间 - 额外补充了窗口拖拽、最大化/最小化/关闭的基础功能,保证窗口正常交互
补充说明
如果需要更贴近原生系统的标题栏样式,可以自行调整控件样式表适配不同系统的设计风格,也可以根据需求增减标题栏里的元素。
内容的提问来源于stack exchange,提问作者CasualDemon
相关产品推荐
相关产品推荐

