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

自定义标题栏窗口中调整Toolbar显示位置的方法

解决方案

你的问题根源在于使用了QMainWindow.addToolBar()方法,这个方法会让Qt自动将工具栏放置到主窗口的默认工具栏区域,而非你手动添加的垂直布局中。同时TitleBar类中存在冗余的标签页和编辑器相关代码,导致逻辑混乱。

以下是具体修改步骤:

1. 清理TitleBar类中的冗余代码

删除TitleBar.__init__中不属于标题栏职责的代码,这些内容应由MainWindow统一管理:

# 删除以下代码块
self.current_editor = self.parent().create_editor()
self.current_editor.setFocus()
self.text_editors = []
self.tabs = qtw.QTabWidget()
self.tabs.setTabsClosable(True) 
self.tabs.tabBar().setMovable(True)

# 同时删除提前调用父类动作创建的代码
self.parent()._createActions()
self.parent()._connectActions()

2. 修改工具栏创建方式

将MainWindow._createToolBars方法改为直接实例化QToolBar,避免使用QMainWindow的默认工具栏管理:

def _createToolBars(self):
    # 直接创建QToolBar作为普通控件,完全由布局控制位置
    self.file_toolbar = qtw.QToolBar("File", self)
    self.file_toolbar.setIconSize(qtc.QSize(22,22))
    self.file_toolbar.addAction(self.new_action)
    self.file_toolbar.addAction(self.open_action)
    self.file_toolbar.addAction(self.save_action)

3. 调整MainWindow初始化顺序

将动作创建代码提前到标题栏实例化之前,确保标题栏的菜单栏能正确获取动作:

def __init__(self):
    super(MainWindow, self).__init__()
    # ... 其他初始化代码 ...
    
    # 先创建动作,再实例化标题栏
    self._createActions()
    self.title_bar = TitleBar(self)
    
    # ... 后续代码 ...

修改后的完整代码

import sys
from PySide6 import QtWidgets as qtw
from PySide6 import QtCore as qtc
from PySide6 import QtGui as qtg


class TitleBar(qtw.QWidget):
    height = 35
    def __init__(self, parent):
        super(TitleBar, self).__init__(parent)

        self.nav_maximize = """
            QToolButton[accessibleName="btn_max"] {
                image: url(./icons/nav_maximize.png);
                background: #161a21;
                border: none;
                padding-right: 3px; 
            }
            QToolButton[accessibleName="btn_max"]:hover {
                image: url(./icons/colored_maximize.png);
                background: #161a21;
                border: none;
            }
        """

        self.nav_normal =  """
                QToolButton[accessibleName="btn_max"]{
                    image: url(./icons/nav_normal.png);
                    background: #161a21;
                    border: none;
                    
                }
                QToolButton[accessibleName="btn_max"]:hover{
                    image: url(./icons/colored_normal.png);
                    background: #161a21;
                    border: none;
                    
                }
            """

        ### 窗口移动相关 ###
        self.prevGeo = self.geometry()
        self.pressing = False
        self.maximizedWindow=False
        ### [ end ] ###
        
        self.layout = qtw.QHBoxLayout()
        self.layout.setContentsMargins(0,0,10,0) 
        
        self.menubar = qtw.QMenuBar()
  
        file_menu = self.menubar.addMenu('File')
        file_menu.addAction(self.parent().new_action)
        file_menu.addAction(self.parent().open_action)
        file_menu.addAction(self.parent().save_action)
        file_menu.addSeparator()
        file_menu.addAction(self.parent().exit_action)

        self.layout.addWidget(self.menubar) 

        self.window_title = qtw.QLabel("Visual Studio Code") # 窗口标题
        self.window_title.setAlignment(qtc.Qt.AlignCenter)
        self.window_title.setAccessibleName("lbl_title") 
        self.window_title.setFixedHeight(self.height)
        self.layout.addStretch(1) # 让标题标签占据剩余空间
        self.layout.addWidget(self.window_title)

        self.setSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Fixed)
        self.maximizedWindow=False
       
        self.closeButton = qtw.QToolButton() 
        self.closeButton.setAccessibleName("btn_close")                           
        self.closeButton.clicked.connect(self.onClickClose)

        self.maxButton = qtw.QToolButton()
        self.maxButton.setAccessibleName("btn_max")  
        self.maxButton.setStyleSheet(self.nav_maximize)
        self.maxButton.clicked.connect(self.showMaxRestore)

        self.hideButton = qtw.QToolButton()
        self.hideButton.setAccessibleName("btn_min")  
        self.hideButton.clicked.connect(self.onClickHide)

        self.layout.addWidget(self.hideButton)
        self.layout.addWidget(self.maxButton)
        self.layout.addWidget(self.closeButton)
        self.setLayout(self.layout)

    #####################################################
    ## 标题栏最小化、最大化、关闭方法
    #####################################################
    def onClickClose(self):
        self.parent().close()
            
    def onClickHide(self):
        self.parent().showMinimized()

    def showMaxRestore(self):
        if(self.maximizedWindow):
            self.parent().showNormal()
            self.maximizedWindow = False
            self.maxButton.setStyleSheet(self.nav_maximize)
        else:
            self.prevGeo = self.parent().geometry()
            self.parent().showMaximized()
            self.maximizedWindow = True
            self.maxButton.setStyleSheet(self.nav_normal)
    
    def mouseReleaseEvent(self, event):
        if event.globalPosition().y() < 10:
            self.showMaxRestore()

    def mousePressEvent(self, event):
        self.prevMousePos = event.scenePosition()
        self.pressing = True
        
        if event.type() == qtc.QEvent.MouseButtonDblClick:
            self.showMaxRestore()

    def mouseMoveEvent(self, event):
        if(self.maximizedWindow): 
                self.parent().showNormal()
                self.maximizedWindow= False
                self.maxButton.setStyleSheet(self.nav_maximize)
                self.prevMousePos = qtc.QPointF((self.prevGeo.width()*.5), (self.prevGeo.height()*.5))

        if self.pressing:
            mousePosition = event.globalPosition()
            pos = mousePosition-self.prevMousePos
            x = pos.x() 
            y = pos.y() 
            self.parent().move(int(x), int(y))
      
    #####################################################
    ##                      END
    #####################################################


class MainWindow(qtw.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.statusbar = self.statusBar()
        self.statusbar.showMessage("Ready")

        self.current_editor = self.create_editor()
        self.current_editor.setFocus()
        self.text_editors = []

        self.setMinimumSize(400,250)
        self.resize(700,500)
        self.setWindowFlags(qtc.Qt.FramelessWindowHint|
                            qtc.Qt.WindowMaximizeButtonHint|
                            qtc.Qt.WindowMinimizeButtonHint |
                            qtc.Qt.WindowStaysOnTopHint
                            )

        # 先创建动作,确保标题栏能获取到
        self._createActions()
        self.title_bar  = TitleBar(self)
        
        self.tabs = qtw.QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabBar().setMovable(True)
        self.tabs.tabCloseRequested.connect(self.remove_editor)
        self.tabs.currentChanged.connect(self.change_text_editor)
        
        self._createToolBars()
        self._connectActions()

        # 构建中央控件布局
        widget = qtw.QWidget()
        layout = qtw.QVBoxLayout()
        layout.setContentsMargins(0,0,0,0)
        layout.addWidget(self.title_bar, 1)
        layout.addWidget(self.file_toolbar, 2)
        layout.addWidget(self.tabs, 3)
        layout.setSpacing(0) 
        widget.setLayout(layout)
     
        self.setCentralWidget(widget)
        self.new_tab()
        self.closeTab()

    def create_editor(self):
        current_editor = qtw.QTextEdit()
        current_editor.setTabStopDistance(33)
        return current_editor

    def change_text_editor(self, index):
        if index < len(self.text_editors):
            self.current_editor = self.text_editors[index]

    def remove_editor(self, index):
        if self.tabs.count() < 2: 
            return True
  
        self.tabs.removeTab(index)
        if index < len(self.text_editors):
            del self.text_editors[index]
        
    def closeTab(self): 
        close_tab = qtg.QShortcut(qtg.QKeySequence("Ctrl+W"), self)
        close_tab.activated.connect(lambda:self.remove_editor(self.tabs.currentIndex()))

    def close(self):
        qtw.QApplication.quit()

    def new_tab(self, checked = False, title = "Untitled.txt"):
        editor_widget = qtw.QWidget()
        editor_layout = qtw.QVBoxLayout(editor_widget)
        editor_layout.setContentsMargins(0,0,0,0)
        
        self.current_editor = self.create_editor()
        self.text_editors.append(self.current_editor)
        editor_layout.addWidget(self.current_editor)
        
        tab_index = self.tabs.addTab(editor_widget, title)
        self.tabs.setCurrentIndex(tab_index)
    
    def open_document(self):
        options = qtw.QFileDialog.Options()
        self.filename, _ = qtw.QFileDialog.getOpenFileName(
            self, 'Open File',".",
            "(*.notes);;Text Files (*.txt);;Python Files (*.py)",
            options=options
        )
        if self.filename:
            with open(self.filename,"rt") as file:
                content = file.read()
                self.current_editor = self.create_editor() 
                self.current_editor.setText(content)
                
                editor_widget = qtw.QWidget()
                editor_layout = qtw.QVBoxLayout(editor_widget)
                editor_layout.setContentsMargins(0,0,0,0)
                editor_layout.addWidget(self.current_editor)
                
                currentIndex = self.tabs.addTab(editor_widget, str(self.filename))
                self.text_editors.append(self.current_editor)
                self.tabs.setCurrentIndex(currentIndex)
                
    def _createToolBars(self):
        self.file_toolbar = qtw.QToolBar("File", self)
        self.file_toolbar.setIconSize(qtc.QSize(22,22))
        self.file_toolbar.addAction(self.new_action)
        self.file_toolbar.addAction(self.open_action)
        self.file_toolbar.addAction(self.save_action)

    def _createActions(self):
        self.new_action = qtg.QAction(qtg.QIcon("./icons/new_file.png"),"New", self)
        self.open_action = qtg.QAction(qtg.QIcon("./icons/folder.png"),"Open", self)
        self.save_action = qtg.QAction(qtg.QIcon("./icons/save.png"),"Save", self)
        self.exit_action = qtg.QAction(qtg.QIcon("./icons/close.png"), "Exit", self)
   
        self.new_action.setShortcut("Ctrl+N")
        self.open_action.setShortcut("Ctrl+O")
        self.save_action.setShortcut("Ctrl+S")
        self.exit_action.setShortcut("Ctrl+Shift+Q")

        self.new_action.setToolTip("New file")
        self.open_action.setToolTip("Open a file")
        self.save_action.setToolTip("Save a file")
        self.exit_action.setToolTip("Exit Program")

    def _connectActions(self):
        self.new_action.triggered.connect(self.new_tab)
        self.open_action.triggered.connect(self.open_document)
        self.save_action.triggered.connect(self.save_document)
        self.exit_action.triggered.connect(self.close)

    def save_document (self):
        if not self.current_editor.document().isModified():
            self.statusBar().showMessage("There are no texts to be saved!")
        else:
            options = qtw.QFileDialog.Options()
            file_filter = 'Notes_ file (*.notes);; Text file (*.txt);; Python file (*.py)'
            if not hasattr(self, 'filename') or not self.filename:
                self.filename = qtw.QFileDialog.getSaveFileName(self,caption='Save File',directory=".",filter=file_filter,initialFilter='Notes Files (*.notes)')[0]
            
            if self.filename:
                with open(self.filename,"wt") as file:
                    file.write(self.current_editor.toHtml())
                    self.tabs.setTabText(self.tabs.currentIndex(), str(self.filename))
                    self.statusBar().showMessage(f"Saved to {self.filename}")
                    
                self.changesSaved = True

if __name__ == "__main__":
    app = qtw.QApplication(sys.argv)
    main = MainWindow()
    main.setStyleSheet(
        """
          QToolButton[accessibleName="btn_close"] {
                image: url(./icons/nav_close.png);
                background: #161a21;
                border: none;
            }
            QToolButton[accessibleName="btn_close"]:hover {
                image: url(./icons/colored_close.png);
                background: #161a21;
                border: none;
            }    
            QToolButton[accessibleName="btn_min"] {
                image: url(./icons/nav_minimize.png);
                background: #161a21;
                border: none;
                padding-right: 3px;
            }
            QToolButton[accessibleName="btn_min"]:hover {
                image: url(./icons/colored_minimize.png);
                background: #161a21;
                border: none;
                padding-right: 3px;
            }
        """
    )
    main.show()
    sys.exit(app.exec())

额外优化说明

  • 将TitleBar中对主窗口的硬编码改为self.parent(),消除全局变量依赖
  • 修正new_tab方法逻辑,用普通QWidget包裹编辑器,替代错误的QMainWindow作为标签页内容
  • 修复save_document中filename属性的判断逻辑,避免属性不存在的报错

内容的提问来源于stack exchange,提问作者adfinem_rising

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:40:37