QMainWindow中Frame与Toolbar重叠问题排查求助
QMainWindow工具栏与Frame重叠问题解决
问题原因
QMainWindow是具有固定结构的特殊窗口,它的顶层布局负责管理工具栏、状态栏等系统组件的位置,不能直接在这个顶层布局中添加业务内容组件。你直接调用self.layout().addWidget(frame)将Frame加入顶层布局,会导致内容与工具栏区域重叠;添加的QSpacerItem也因为作用于顶层布局,无法起到分隔工具栏和内容的作用。
解决办法
必须通过QMainWindow的**中央部件(Central Widget)**来承载所有业务内容,QMainWindow会自动维护工具栏与中央部件的位置关系,避免重叠。具体步骤:
- 创建一个QWidget作为中央部件,通过
setCentralWidget()绑定到主窗口 - 给中央部件设置一个布局(如QVBoxLayout)
- 将所有动态生成的Frame添加到中央部件的布局中
修改后的完整代码
class MainWindow(QMainWindow): """ Main application window """ def __init__(self, settings): try: QMainWindow.__init__(self) self.settings_window = None self.settings = settings self.setMinimumSize(QSize(700, 700)) self.setWindowTitle("Titan Quest Modding Advanced - TQMA") # 创建工具栏并添加到主窗口 toolbar = QToolBar("Main toolbar") self.addToolBar(toolbar) # 设置中央部件及布局 central_widget = QWidget(self) self.setCentralWidget(central_widget) self.central_layout = QVBoxLayout(central_widget) # 添加设置动作 settings_action = QAction("Settings", self) settings_action.setStatusTip("Edit settings") settings_action.triggered.connect(self.get_settings_window) toolbar.addAction(settings_action) # 动态创建Frame及对应动作 for frame_name in ["Mod merge", "Mod manager"]: frame = QFrame(self, objectName=frame_name) layout = QVBoxLayout(frame) test_button = QPushButton(frame_name, frame) layout.addWidget(test_button) frame.setLayout(layout) frame.hide() frame_action = QAction(frame_name, self) frame_action.setStatusTip(frame_name) frame_action.triggered.connect( lambda checked, frame_name=frame_name: self.show_frame_by_name(frame_name) ) toolbar.addAction(frame_action) # 将Frame添加到中央部件的布局中 self.central_layout.addWidget(frame) except Exception as exc: traceback_formatted = traceback.format_exc() logger.info(traceback_formatted) raise RuntimeError(traceback_formatted) from exc def get_settings_window(self): """ Generates and shows settings window from which the settings can be edited """ self.settings_window = SettingsWindow(self.settings) self.settings_window.setWindowModality(Qt.WindowModality.ApplicationModal) self.settings_window.show() def show_frame_by_name(self, frame_name): """ Takes a frame name as an input parameter. Searches main window for that frame and returns it """ frames_to_hide = self.findChildren(QFrame) for frame in frames_to_hide: frame.hide() frame_to_show = self.findChild(QFrame, frame_name) logger.debug(f"Found frame: {frame_to_show}") if frame_to_show: frame_to_show.show()
额外说明
- 中央部件的布局会自动填充工具栏下方的整个内容区域,窗口大小变化时也会自动适配
- 原有的
show_frame_by_name方法逻辑无需修改,依然可以正常切换Frame的显示状态
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

