主窗口提供了用于构建应用程序的用户界面的框架,其主要布局如下
Menu Bar:菜单栏,通过添加QMenuBar
# 实例化QMenuBarself.menuBarInstance = QMenuBar(self)# 创建菜单fileMenu = self.menuBarInstance.addMenu("文件")# 创建动作exitAction = QAction("退出", self)exitAction.triggered.connect(self.close)# 将动作添加到菜单fileMenu.addAction(exitAction)
# 实例化QToolBartoolBar = QToolBar("我的工具栏", self)self.addToolBar(toolBar)# 创建动作exitAction = QAction("退出", self)exitAction.triggered.connect(self.close)# 将动作添加到菜单fileMenu.addAction(exitAction)
# 创建一个QDockWidgetdock = QDockWidget("菜单", self)self.addDockWidget(Qt.LeftDockWidgetArea, dock)# 创建一个列表作为菜单项容器menuList = QListWidget()dock.setWidget(menuList)
# 实例化一个QWidget作为中心部件centralWidget = QWidget()self.setCentralWidget(centralWidget)# 创建一个布局layout = QVBoxLayout()# 添加一些控件到布局中layout.addWidget(QLabel("这是一个标签"))# 将布局设置给中心部件centralWidget.setLayout(layout)
# 实例化一个QStatusBarstatusBar = QStatusBar()# 将状态栏设置为主窗口的状态栏self.setStatusBar(statusBar)# 在状态栏中添加一些信息statusBar.addWidget(QLabel("这是状态栏信息"))
2、QMainWindow常用属性和方法
属性windowTitle::窗口的标题。menuBar:窗口的菜单栏。statusBar:窗口的状态栏。centralWidget:窗口的中心部件。toolBars:窗口的工具栏列表。dockWidgets:窗口的停靠窗口列表。animated:操作停靠小部件和工具栏是否有动画dockNestingEnabled:停靠部件是否可以嵌套dockOptions:QMainWindow的停靠行为documentMode:选项卡式停靠小部件的选项卡栏是否设置为文档模式iconSize:此主窗口中工具栏图标的大小tabShape:用于选项卡式停靠小部件的选项卡形状toolButtonStyle:主窗口中工具栏按钮的样式unifiedTitleAndToolBarOnMac:窗口是否在macOS上使用统一的标题和工具栏外观方法setWindowFlags(Qt.WindowFlags flags):用于指定窗口的各种属性和行为。例如,你可以设置窗口为无边框、始终在顶层显示、不显示在任务栏等窗口装饰标志

Qt.MSWindowsFixedSizeDialogHint
Windows平台上,使对话框窗口的大小固定,不能被用户调整。
Qt.X11BypassWindowManagerHint
在X11平台(Linux/Unix)上,使窗口绕过窗口管理器,直接与系统交互。这通常用于需要完全控制窗口显示和行为的特殊窗口
Qt.FramelessWindowHint
创建一个无边框窗口。这通常用于自定义窗口的外观。
Qt.NoDropShadowWindowHint
禁用窗口的阴影效果。这在自定义窗口绘制时可能有用,特别是在需要精确控制窗口外观的情况下。
Qt.WindowTitleHint
窗口将包含一个标题栏。这是大多数窗口的默认行为。
Qt.WindowSystemMenuHint
窗口将包含一个系统菜单,通常位于标题栏的左上角。
Qt.WindowMinimizeButtonHint
窗口将包含一个最小化按钮。
Qt.WindowMaximizeButtonHint
窗口将包含一个最大化按钮。
Qt.WindowCloseButtonHint
窗口将包含一个关闭按钮。
Qt.WindowContextHelpButtonHint
窗口将包含一个上下文帮助按钮,在用户点击时通常会显示帮助信息。
Qt.WindowStaysOnTopHint
窗口将始终保持在其他窗口之上。
Qt.WindowStaysOnBottomHint
窗口将始终保持在其他窗口之下。
Qt.CustomizeWindowHint
允许窗口被自定义,通常与其他窗口标志一起使用,以提供特定的窗口外观和行为。
常用窗口标志
Qt.Widget
默认值,指示对象是一个控件
Qt.Window
使控件成为一个窗口,这会给它提供窗口装饰
Qt.Dialog
示窗口是一个对话框
Qt.Sheet
指示窗口是一个Mac风格的表单(仅在Mac OS X中有效)
Qt.Drawer
指示窗口是一个Mac风格的抽屉(仅在Mac OS X中有效)
Qt.Popup
指示窗口是一个弹出窗口
Qt.Tool
指示窗口是一个工具窗口。工具窗口是一个小窗口,通常用于提供模式或非模式对话框
Qt.ToolTip
指示窗口是一个工具提示
Qt.SplashScreen
指示窗口是一个启动画面
Qt.Desktop
指示窗口是桌面。这是一个特殊的窗口,不能创建
Qt.SubWindow
指示窗口是一个子窗口
addDockWidget(area, dockwidget, orientation): 在指定区域和方向添加一个停靠窗口。以下是停靠的枚举值常用的停靠窗口标志
QMainWindow.AnimatedDocks
与属性相同animated。
QMainWindow.AllowNestedDocks
与属性相同dockNestingEnabled。
QMainWindow.AllowTabbedDocks
用户可以将一个停靠小部件放置在另一个停靠小部件的“顶部”。这两个小部件堆叠在一起,并出现一个选项卡栏,用于选择哪个小部件可见。
QMainWindow.ForceTabbedDocks
每个停靠区域都包含一堆选项卡式停靠小部件。换句话说,停靠小部件不能在停靠区域中彼此相邻放置。如果设置此选项,AllowNestedDocks 不起作用。
QMainWindow.VerticalTabs
主窗口两侧的两个垂直停靠区域垂直显示其选项卡。如果未设置此选项,所有停靠区域都会在底部显示其选项卡。暗示AllowTabbedDocks。也可以看看setTabPosition()。
QMainWindow.GroupedDragging
拖动扩展坞的标题栏时,所有与其关联的选项卡都将被拖动。暗示AllowTabbedDocks。如果某些 QDockWidget 在允许的区域有限制,则效果不佳。(这个枚举值是在 Qt 5.6 中添加的。)
addDockWidget(area, dockwidget): 在指定区域添加一个停靠窗口。addToolBar(area, toolbar): 在指定区域添加一个工具栏。addToolBar(title): 创建一个新的工具栏,使用提供的标题。addToolBar(toolbar): 添加一个预先创建的工具栏。addToolBarBreak([area=Qt.TopToolBarArea]): 在指定区域添加一个工具栏断点。centralWidget(): 返回当前设置为中心部件的QWidget对象。corner(corner): 返回指定角落的停靠区域。dockOptions(): 返回当前的停靠选项。dockWidgetArea(dockwidget): 返回指定停靠窗口所在的区域。documentMode(): 返回文档模式的启用状态。iconSize(): 返回工具栏图标的大小。insertToolBar(before, toolbar): 在指定的工具栏之前插入一个工具栏。insertToolBarBreak(before): 在指定的工具栏之前插入一个工具栏断点。isAnimated(): 返回窗口是否启用动画。isDockNestingEnabled(): 返回是否允许停靠窗口嵌套。isSeparator(pos): 检查指定位置是否为分隔符。menuBar(): 返回窗口的菜单栏。menuWidget(): 返回设置为菜单栏的自定义QWidget对象。removeDockWidget(dockwidget): 移除指定的停靠窗口。removeToolBar(toolbar): 移除指定的工具栏。removeToolBarBreak(before): 移除指定位置的工具栏断点。resizeDocks(docks, sizes, orientation): 调整一组停靠窗口的大小。restoreDockWidget(dockwidget): 恢复停靠窗口的状态。restoreState(state[, version=0]): 恢复窗口的状态。saveState([version=0]): 保存窗口的当前状态。setCentralWidget(widget): 设置中心部件。setCorner(corner, area): 设置窗口角落的停靠区域。setDockOptions(options): 设置停靠选项。setDocumentMode(enabled): 启用或禁用文档模式。setIconSize(iconSize): 设置工具栏图标的大小。setMenuBar(menubar): 设置窗口的菜单栏。setMenuWidget(menubar): 设置自定义的菜单栏部件。setStatusBar(statusbar): 设置窗口的状态栏。setTabPosition(areas, tabPosition): 设置停靠窗口的标签位置。setTabShape(tabShape): 设置停靠窗口的标签形状。setToolButtonStyle(toolButtonStyle): 设置工具按钮的样式。splitDockWidget(after, dockwidget, orientation): 将一个停靠窗口分割为两个。statusBar(): 返回窗口的状态栏。tabPosition(area): 返回指定区域的标签位置。tabShape(): 返回停靠窗口的标签形状。tabifiedDockWidgets(dockwidget): 返回与指定停靠窗口标签化的所有停靠窗口。tabifyDockWidget(first, second): 将两个停靠窗口标签化。takeCentralWidget(): 移除并返回中心部件。toolBarArea(toolbar): 返回指定工具栏所在的区域toolBarBreak(toolbar): 检查指定工具栏之前是否有工具栏断点。toolButtonStyle(): 返回工具按钮的样式。unifiedTitleAndToolBarOnMac(): 返回是否在Mac OS上使用统一的标题栏和工具栏样式。createPopupMenu(): 创建一个包含所有可停靠窗口和工具栏的可见性控制项的弹出菜单。这个方法通常用于提供一个上下文菜单,允许用户选择哪些工具栏或停靠窗口是可见的。3、QMainWindow图标和背景设置
设置logo图标# 设置窗口图标self.setWindowIcon(QIcon('path/to/your/icon.png'))
设置背景通过样式设置颜色
# 使用样式表设置背景颜色self.setStyleSheet("background-color: lightblue;")
通过样式设置图片
# 使用样式表设置背景图片self.setStyleSheet("background-image: url('path/to/your/image.jpg');")
通过QPainter绘制背景图片
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("通过paintEvent设置背景") def paintEvent(self, event): painter = QPainter(self) pixmap = QPixmap("path/to/your/image.jpg") P·ainter.drawPixmap(self.rect(), pixmap)if __name__ == "__main__": app = QApplication(sys.argv) mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_())
4、QMainWindow无边框设计实现
实现无边框设计,pyside6目前没有很好的解决方案。主要思路是设置无边框,通过自定义标题栏来实现窗口的基本属性,事件。下面是具体例子:
from PySide6.QtCore import QSize, Qt, QEventfrom PySide6.QtGui import QPalette, QRegionfrom PySide6.QtWidgets import class CustomTitleBar(QWidget): def __init__(self, parent): super().__init__(parent) self.setAutoFillBackground(True) self.setBackgroundRole(QPalette.ColorRole.Highlight) self.initial_pos = None title_bar_layout = QHBoxLayout(self) title_bar_layout.setContentsMargins(1, 1, 1, 1) title_bar_layout.setSpacing(2) self.title = QLabel("自定义工具栏", self) self.title.setStyleSheet( """font-weight: bold; border: 2px solid black; border-radius: 12px; margin: 2px; """ ) self.title.setAlignment(Qt.AlignmentFlag.AlignCenter) if title := parent.windowTitle(): self.title.setText(title) # 只设置自定义标题拖动 self.title.mousePressEvent = parent.title_mousePressEvent self.title.mouseMoveEvent = parent.title_mouseMoveEvent self.title.mouseReleaseEvent = parent.title_mouseReleaseEvent title_bar_layout.addWidget(self.title) # Min button self.min_button = QToolButton(self) min_icon = self.style().standardIcon( QStyle.StandardPixmap.SP_TitleBarMinButton ) self.min_button.setIcon(min_icon) self.min_button.clicked.connect(self.window().showMinimized) # Max button self.max_button = QToolButton(self) max_icon = self.style().standardIcon( QStyle.StandardPixmap.SP_TitleBarMaxButton ) self.max_button.setIcon(max_icon) self.max_button.clicked.connect(self.window().showMaximized) # Close button self.close_button = QToolButton(self) close_icon = self.style().standardIcon( QStyle.StandardPixmap.SP_TitleBarCloseButton ) self.close_button.setIcon(close_icon) self.close_button.clicked.connect(self.window().close) # Normal button self.normal_button = QToolButton(self) normal_icon = self.style().standardIcon( QStyle.StandardPixmap.SP_TitleBarNormalButton ) self.normal_button.setIcon(normal_icon) self.normal_button.clicked.connect(self.window().showNormal) self.normal_button.setVisible(False) # Add buttons buttons = [ self.min_button, self.normal_button, self.max_button, self.close_button, ] for button in buttons: button.setFocusPolicy(Qt.FocusPolicy.NoFocus) button.setFixedSize(QSize(28, 28)) button.setStyleSheet( """QToolButton { border: 2px solid white; border-radius: 12px; } """ ) title_bar_layout.addWidget(button) def window_state_changed(self, state): if state == Qt.WindowState.WindowMaximized: self.normal_button.setVisible(True) self.max_button.setVisible(False) else: self.normal_button.setVisible(False) self.max_button.setVisible(True)class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Custom Title Bar") self.setMinimumSize(600, 400) self.setWindowFlags(Qt.FramelessWindowHint) # 使用QSS设置边框样式为圆角 self.setStyleSheet("MainWindow{border-radius: 1px;}") central_widget = QWidget() self.title_bar = CustomTitleBar(self) work_space_layout = QVBoxLayout() work_space_layout.setContentsMargins(11, 11, 11, 11) work_space_layout.addWidget(QLabel("Hello, World!", self)) centra_widget_layout = QVBoxLayout() centra_widget_layout.setContentsMargins(0, 0, 0, 0) centra_widget_layout.setAlignment(Qt.AlignmentFlag.AlignTop) centra_widget_layout.addWidget(self.title_bar) centra_widget_layout.addLayout(work_space_layout) central_widget.setLayout(centra_widget_layout) self.setCentralWidget(central_widget) def changeEvent(self, event): if event.type() == QEvent.Type.WindowStateChange: self.title_bar.window_state_changed(self.windowState()) super().changeEvent(event) event.accept() def window_state_changed(self, state): self.normal_button.setVisible(state == Qt.WindowState.WindowMaximized) self.max_button.setVisible(state != Qt.WindowState.WindowMaximized) def title_mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.initial_pos = event.position().toPoint() super().mousePressEvent(event) event.accept() def title_mouseMoveEvent(self, event): if self.initial_pos is not None: delta = event.position().toPoint() - self.initial_pos self.window().move( self.window().x() + delta.x(), self.window().y() + delta.y(), ) super().mouseMoveEvent(event) event.accept() def title_mouseReleaseEvent(self, event): self.initial_pos = None super().mouseReleaseEvent(event) event.accept()if __name__ == "__main__": app = QApplication([]) window = MainWindow() window.show() app.exec()
效果如下,可以实现放大,缩小,标题栏拖动功能:
效果图
上面例子没有实现窗口边框可拖动放大缩小的功能,是个遗憾。github上的有实现,可以参考:https://github.com/alexpdev/QtFrameless。