Python-GUI-wxPython-容器

1 需求

  • wx.App
  • wx.Frame
  • wx.Panel

2 接口

在 wxPython 中,容器类控件是用于组织和管理其他控件的基础组件。它们提供了布局管理、嵌套结构和视觉分组的功能。以下是 wxPython 中主要容器类控件的分类介绍:

1. 顶级窗口容器

wx.Frame

  • 描述:应用程序的主窗口,可包含菜单栏、工具栏和状态栏。
  • 特点:独立窗口,可最大化、最小化、关闭。
  • 用途:作为应用程序的主界面。

wx.Dialog

  • 描述:模态或非模态对话框,用于短期交互。
  • 特点:通常无菜单栏,可包含按钮面板。
  • 用途:弹出式设置窗口、消息提示框。

wx.SplashScreen

  • 描述:启动画面,显示应用程序加载时的信息。
  • 用途:应用程序启动时展示版权、加载进度等。

2. 面板容器

wx.Panel

  • 描述:基础面板,用于组织控件和处理事件。
  • 特点
    • 提供独立的绘制区域和事件处理。
    • 通常作为其他控件的父容器。
    • 支持背景色、边框等样式。
  • 用途:将界面划分为逻辑区域(如表单、工具栏下方的内容区)。

wx.ScrolledPanel

  • 描述:带滚动条的面板,内容超出范围时自动显示滚动条。
  • 特点:继承自 wx.Panel,支持自动滚动。
  • 用途:显示大量内容(如长表单、大型图表)。

3. 分栏容器

wx.SplitterWindow

  • 描述:可分割的窗口,支持水平或垂直分割。
  • 特点
    • 分隔条可拖动调整大小。
    • 支持嵌套分割(如左右分栏后再上下分栏)。
  • 用途:资源管理器式的界面(左侧目录树,右侧内容区)。

4. 选项卡容器

wx.Notebook

  • 描述:选项卡控件,通过标签页切换不同内容。
  • 特点
    • 标签页可位于顶部、底部、左侧或右侧。
    • 支持动态添加 / 删除标签页。
  • 用途:多页面应用(如浏览器标签、设置面板)。

wx.Toolbook

  • 描述:类似 wx.Notebook,但使用工具栏按钮替代标签页。
  • 特点:标签页按钮可自定义图标和样式。
  • 用途:需要更大按钮或自定义样式的选项卡界面。

5. 分组容器

wx.StaticBox

  • 描述:带标题的边框,用于视觉分组。
  • 特点
    • 通常与 wx.StaticBoxSizer 配合使用。
    • 提供视觉上的逻辑分组。
  • 用途:表单中的字段分组(如个人信息、联系方式)。

wx.CollapsiblePane

  • 描述:可折叠的面板,点击标题可展开 / 折叠内容。
  • 特点:节省空间,适合包含可选内容。
  • 用途:高级设置面板、可收起的详情区域。

6. 特殊容器

wx.aui.AuiNotebook

  • 描述:高级选项卡控件,支持拖拽标签页、浮动窗口。
  • 特点
    • 比 wx.Notebook 更灵活,支持多文档界面(MDI)。
    • 常用于专业软件(如 IDE、图形编辑器)。

wx.lib.agw.pybusyinfo.PyBusyInfo

  • 描述:临时覆盖窗口,显示进度或忙碌状态。
  • 用途:长时间操作时防止用户交互(如文件上传)。

容器选择指南

  • 需要独立窗口:使用 wx.Frame 或 wx.Dialog
  • 组织控件布局:使用 wx.Panel 或 wx.ScrolledPanel
  • 多区域分割:使用 wx.SplitterWindow
  • 选项卡界面:使用 wx.Notebook 或 wx.Toolbook
  • 视觉分组:使用 wx.StaticBox 或 wx.CollapsiblePane
  • 高级界面:使用 wx.aui.AuiNotebook

3.1 容器:wx.App

import wxapp = wx.App()frame = wx.Frame(None, title="wxPython Demo")frame.Show()app.MainLoop()

3.2 容器:wx.Frame

示例:

  • 设置窗口图标
  • 设置窗口居中
  • 设置窗口最大化
import wxapp = wx.App(False)frame = wx.Frame(parent=None,id=wx.ID_ANY,title="wxPython Demo",pos=wx.DefaultPosition,size=wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE,name="mFrame"
)# 设置窗口图标
icon = wx.Icon("res/img/dsl.ico", wx.BITMAP_TYPE_ICO)
frame.SetIcon(icon)# 设置窗口居中
frame.Center()# 设置窗口最大化
frame.Maximize()# 设置显示窗口
frame.Show()# 设置启动主循环
app.MainLoop()

3.3 容器:wx.Panel

import wxclass MainFrame(wx.Frame):def __init__(self, *args, **kwargs):super(MainFrame, self).__init__(*args, **kwargs)self.init_ui()self.Center()self.Maximize()def init_ui(self):panel = wx.Panel(self)sizer = wx.BoxSizer(wx.VERTICAL)btn = wx.Button(panel, label="Hello World")sizer.Add(btn)panel.SetSizer(sizer)if __name__ == "__main__":app = wx.App()frame = MainFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

4.* 容器:wx.Dialog

import wxclass LoginDialog(wx.Dialog):"""自定义登录对话框"""def __init__(self, parent, title):super().__init__(parent, title=title, size=(300, 200))# 创建面板panel = wx.Panel(self)# 创建垂直布局sizer = wx.BoxSizer(wx.VERTICAL)# 添加用户名输入user_sizer = wx.BoxSizer(wx.HORIZONTAL)user_label = wx.StaticText(panel, label="用户名:")self.username = wx.TextCtrl(panel)user_sizer.Add(user_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)user_sizer.Add(self.username, 1, wx.ALL, 5)sizer.Add(user_sizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)# 添加密码输入pass_sizer = wx.BoxSizer(wx.HORIZONTAL)pass_label = wx.StaticText(panel, label="密码:")self.password = wx.TextCtrl(panel, style=wx.TE_PASSWORD)pass_sizer.Add(pass_label, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)pass_sizer.Add(self.password, 1, wx.ALL, 5)sizer.Add(pass_sizer, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)# 添加记住密码复选框self.remember = wx.CheckBox(panel, label="记住密码")sizer.Add(self.remember, 0, wx.ALL | wx.LEFT, 15)# 添加按钮btn_sizer = wx.StdDialogButtonSizer()ok_btn = wx.Button(panel, wx.ID_OK)ok_btn.SetDefault()cancel_btn = wx.Button(panel, wx.ID_CANCEL)btn_sizer.AddButton(ok_btn)btn_sizer.AddButton(cancel_btn)btn_sizer.Realize()sizer.Add(btn_sizer, 0, wx.ALL | wx.EXPAND, 10)panel.SetSizer(sizer)def get_username(self):"""获取用户名"""return self.username.GetValue()def get_password(self):"""获取密码"""return self.password.GetValue()def get_remember(self):"""获取是否记住密码"""return self.remember.GetValue()class MainFrame(wx.Frame):"""主窗口"""def __init__(self, parent, title):super().__init__(parent, title=title, size=(400, 300))panel = wx.Panel(self)sizer = wx.BoxSizer(wx.VERTICAL)# 添加登录按钮login_btn = wx.Button(panel, label="登录")login_btn.Bind(wx.EVT_BUTTON, self.on_login)sizer.Add(login_btn, 0, wx.ALL | wx.ALIGN_CENTER, 20)# 添加结果显示区域self.result_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY)sizer.Add(self.result_text, 1, wx.ALL | wx.EXPAND, 10)panel.SetSizer(sizer)self.Center()self.Show()def on_login(self, event):"""显示登录对话框"""with LoginDialog(self, "用户登录") as dlg:result = dlg.ShowModal()if result == wx.ID_OK:username = dlg.get_username()password = dlg.get_password()remember = dlg.get_remember()message = f"登录信息:\n"message += f"用户名: {username}\n"message += f"密码: {password}\n"message += f"记住密码: {'是' if remember else '否'}"self.result_text.SetValue(message)if __name__ == "__main__":app = wx.App()frame = MainFrame(None, "wx.Dialog 示例")app.MainLoop()

4.* 容器:wx.MessageDialog

import wxclass MyFrame(wx.Frame):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.init_ui()self.Center()self.Maximize()def init_ui(self):panel = wx.Panel(self)sizer = wx.BoxSizer(wx.VERTICAL)button = wx.Button(panel, label="Button")sizer.Add(button,proportion=0,flag=wx.ALL | wx.EXPAND,border=5)panel.SetSizer(sizer)button.Bind(wx.EVT_BUTTON, self.on_msg_dlg, button)def on_msg_dlg(self, event):dlg = wx.MessageDialog(self, "内容", "标题", wx.OK)dlg.ShowModal()dlg.Destroy()if __name__ == "__main__":app = wx.App()frame = MyFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

4.* 容器:wx.FileDialog

import wxclass FileDialogDemo(wx.Frame):def __init__(self, parent, title):super().__init__(parent, title=title, size=(600, 400))panel = wx.Panel(self)sizer = wx.BoxSizer(wx.VERTICAL)# 创建按钮区域btn_sizer = wx.BoxSizer(wx.HORIZONTAL)# 打开单个文件按钮self.btn_open_file = wx.Button(panel, label="打开单个文件")self.btn_open_file.Bind(wx.EVT_BUTTON, self.on_open_file)btn_sizer.Add(self.btn_open_file, 0, wx.ALL, 10)# 打开多个文件按钮self.btn_open_files = wx.Button(panel, label="打开多个文件")self.btn_open_files.Bind(wx.EVT_BUTTON, self.on_open_files)btn_sizer.Add(self.btn_open_files, 0, wx.ALL, 10)# 保存文件按钮self.btn_save_file = wx.Button(panel, label="保存文件")self.btn_save_file.Bind(wx.EVT_BUTTON, self.on_save_file)btn_sizer.Add(self.btn_save_file, 0, wx.ALL, 10)# 选择目录按钮self.btn_select_dir = wx.Button(panel, label="选择目录")self.btn_select_dir.Bind(wx.EVT_BUTTON, self.on_select_dir)btn_sizer.Add(self.btn_select_dir, 0, wx.ALL, 10)sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER | wx.TOP, 20)# 创建结果显示区域self.result_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY)sizer.Add(self.result_text, 1, wx.ALL | wx.EXPAND, 10)panel.SetSizer(sizer)self.Center()self.Show()def on_open_file(self, event):"""打开单个文件对话框"""with wx.FileDialog(self, "选择文件", wildcard="所有文件 (*.*)|*.*|文本文件 (*.txt)|*.txt|图片文件 (*.png;*.jpg)|*.png;*.jpg",style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as file_dialog:if file_dialog.ShowModal() == wx.ID_CANCEL:return  # 用户取消了操作# 获取选择的文件路径path = file_dialog.GetPath()self.result_text.SetValue(f"选择的文件路径:\n{path}")def on_open_files(self, event):"""打开多个文件对话框"""with wx.FileDialog(self, "选择多个文件", wildcard="所有文件 (*.*)|*.*|文本文件 (*.txt)|*.txt|图片文件 (*.png;*.jpg)|*.png;*.jpg",style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as file_dialog:if file_dialog.ShowModal() == wx.ID_CANCEL:return  # 用户取消了操作# 获取所有选择的文件路径paths = file_dialog.GetPaths()result = "选择的文件路径:\n" + "\n".join(paths)self.result_text.SetValue(result)def on_save_file(self, event):"""保存文件对话框"""with wx.FileDialog(self, "保存文件", wildcard="文本文件 (*.txt)|*.txt|Python文件 (*.py)|*.py|所有文件 (*.*)|*.*",style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as file_dialog:if file_dialog.ShowModal() == wx.ID_CANCEL:return  # 用户取消了操作# 获取保存的文件路径path = file_dialog.GetPath()self.result_text.SetValue(f"文件将保存到:\n{path}")# 实际应用中,这里应该有保存文件的代码# 例如:# try:#     with open(path, 'w') as f:#         f.write("这是示例内容")# except Exception as e:#     wx.MessageBox(f"保存文件失败: {str(e)}", "错误", wx.ICON_ERROR)def on_select_dir(self, event):"""选择目录对话框"""with wx.DirDialog(self, "选择目录", style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST) as dir_dialog:if dir_dialog.ShowModal() == wx.ID_CANCEL:return  # 用户取消了操作# 获取选择的目录路径path = dir_dialog.GetPath()self.result_text.SetValue(f"选择的目录路径:\n{path}")if __name__ == "__main__":app = wx.App()frame = FileDialogDemo(None, "FileDialog 示例")app.MainLoop()

3.* 容器:wx.StaticBox

import wxclass MyFrame(wx.Frame):def __init__(self, *args, **kwargs):super(MyFrame, self).__init__(*args, **kwargs)self.init_ui()self.Center()self.Maximize()def init_ui(self):panel = wx.Panel(self)sizer = wx.BoxSizer(wx.VERTICAL)static_box = wx.StaticBox(parent=panel,id=wx.ID_ANY,label="通用",pos=wx.DefaultPosition,size=wx.DefaultSize,style=0,name="mStaticBox")static_box_sizer = wx.StaticBoxSizer(static_box, wx.VERTICAL)# 第一行first_row_sizer = wx.BoxSizer(wx.HORIZONTAL)cb1 = wx.CheckBox(panel, label="全选")first_row_sizer.Add(cb1, 0, wx.ALL, 5)# 第二行second_row_sizer = wx.BoxSizer(wx.HORIZONTAL)cb2 = wx.CheckBox(panel, label="插件1")cb3 = wx.CheckBox(panel, label="插件2")second_row_sizer.Add(cb2, 0, wx.ALL, 5)second_row_sizer.Add(cb3, 0, wx.ALL, 5)#static_box_sizer.Add(first_row_sizer, 0, flag=wx.ALL, border=5)static_box_sizer.Add(second_row_sizer, 0, flag=wx.ALL, border=5)#sizer.Add(static_box_sizer, 0, flag=wx.ALL | wx.EXPAND, border=10)panel.SetSizer(sizer)if __name__ == "__main__":app = wx.App()frame = MyFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

5.* 示例:菜单栏

import wxclass MainFrame(wx.Frame):ID_SCAN_SETTING = wx.Window.NewControlId()def __init__(self, *args, **kw):super(MainFrame, self).__init__(*args, **kw)self.init_ui()self.Center()self.Maximize()def init_ui(self):self.create_menu_bar()def create_menu_bar(self):# 创建菜单栏menu_bar = wx.MenuBar()# 文件菜单file_menu = wx.Menu()exit_item = file_menu.Append(wx.ID_EXIT, "Exit")# 设置菜单setting_menu = wx.Menu()scan_setting_item = setting_menu.Append(self.ID_SCAN_SETTING, "Scan Setting")# 工具菜单tool_menu = wx.Menu()# 帮助菜单help_menu = wx.Menu()about_item = help_menu.Append(wx.ID_ABOUT, "About")# 添加菜单到菜单栏menu_bar.Append(file_menu, "File")menu_bar.Append(setting_menu, "Setting")menu_bar.Append(tool_menu, "Tool")menu_bar.Append(help_menu, "Help")# 设置菜单栏self.SetMenuBar(menu_bar)# 绑定菜单项事件self.Bind(wx.EVT_MENU, self.on_exit, exit_item)self.Bind(wx.EVT_MENU, self.on_about, about_item)def on_exit(self, event):"""处理退出菜单项点击事件"""# 创建确认对话框(是/否按钮 + 问号图标)dialog = wx.MessageDialog(self, "Are you sure you want to exit?", "Confirm Exit",style=wx.YES_NO | wx.YES_DEFAULT)# 显示对话框并获取结果result = dialog.ShowModal()if result == wx.ID_YES:self.Destroy()else:dialog.Destroy()def on_about(self, event):"""处理关于菜单项点击事件"""dialog = wx.MessageDialog(self, "V0.1.20250701", "Version", wx.OK)dialog.ShowModal()dialog.Destroy()if __name__ == "__main__":app = wx.App()frame = MainFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

5.* 示例:工具栏

import wxclass MainFrame(wx.Frame):def __init__(self, *args, **kw):super(MainFrame, self).__init__(*args, **kw)self.init_ui()self.Center()self.Maximize()def init_ui(self):self.create_tool_bar()def create_tool_bar(self):# 创建工具栏toolbar = self.CreateToolBar()# 添加工具按钮exit_tool = toolbar.AddTool(wx.ID_EXIT, "Exit", wx.ArtProvider.GetBitmap(wx.ART_QUIT))# 启用工具栏toolbar.Realize()# 绑定工具栏事件self.Bind(wx.EVT_TOOL, self.on_exit, exit_tool)def on_exit(self, event):self.Close()if __name__ == "__main__":app = wx.App()frame = MainFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

5.* 示例:状态栏

import wxclass MainFrame(wx.Frame):def __init__(self, *args, **kw):super(MainFrame, self).__init__(*args, **kw)self.init_ui()self.Center()self.Maximize()def init_ui(self):self.CreateStatusBar()self.SetStatusText("ready")if __name__ == "__main__":app = wx.App()frame = MainFrame(None, title="wxPython Demo")frame.Show()app.MainLoop()

4 参考资料