You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:36:00