- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
在开发一套系统框架的时候,除了关注实现系统的功能实现外,我们对于系统的各个方面都是应该精益求精,以最少的编码做最好的事情,在开发的各个层次上,包括前端后端,界面处理、后端处理、常用辅助类、控件封装等等方面,我们都可以通过抽象、重用等方式,实现代码的优化、简化,以期达到快速开发的目的。本篇随笔我们就来聊聊界面的抽象迭代处理,以及最终的实现过程.
例如对于系统的窗体来说,一般我们可以按主要的功能视图来区分,一个是列表展示界面,一个是编辑/查看详细内容界面,前面有一篇文章《使用wxpython开发跨平台桌面应用,基类对话框窗体的封装处理》我专门介绍了编辑对话框的抽象设计,所以本篇随笔主要针对列表界面进行介绍.
如我们大致需要一个展示列表的界面,列表界面一般分为查询区、列表界面展示区和分页信息区,我们把它分为两个主要的部分,如下界面所示.
对于查询条件标号为1区的内容,又可以继续细分,根据不同的业务模块,内容有变化区和固定区,如下标识.
不同的业务模块,查询的条件肯定是不同的,这部分为内容变化区.
而对于常见的功能按钮,基本上是固定的,我们后期可以根据一些条件进行动态的按钮显示/隐藏,但是这里业务按钮就这些,虽然触发的界面肯定有所不同,但是这些按钮的处理逻辑是不会变化的,所以称为固定逻辑区.
对于内容变化的,我们可以把它们下发到子类里面,每一个业务模块的列表界面为一个子类,继承基类即可.
其中业务列表窗体界面分为两个部分 。
而对于通过wx.Grid展示的列表界面部分,虽然分为列表内容和分页栏内容,但是它们的数据变化,控件却是不会变化的,如下界面截图所示.
也就是说,这些控件的相关排版信息,我们可以抽象到父类中进行创建,而数据则由子类进行更新变化即可.
其中包括表格的列名、中文名称对应、列的宽度,数据集合等信息,而分页栏这是根据每页的大小、当前页码、总数等信息进行按钮的状态控制即可.
。
我在文章《基于SqlAlchemy+Pydantic+FastApi的Python开发框架》 中介绍过使用泛型来构建更加弹性化的基类处理.
如对于路由器,我们通过泛型参数的处理,让基类的接口更加个性化一些,如下代码所示.
在 Python 中,泛型(Generic) 是一种允许类型参数化的特性,通常用于类型注解和类型检查。Python 的泛型支持主要通过 typing 模块中的类型提示来实现,例如 Generic、TypeVar、List[T] 等。使用泛型定义基类有以下几个好处:
泛型允许在编写类和函数时,明确指定类型参数,这样在使用时可以进行更严格的类型检查,减少类型错误.
如果基类使用了泛型 T,这样在子类或实例化时可以指定具体的类型(如 User),从而在编译期(使用 IDE 或类型检查工具时)获得类型安全性,避免类型错误.
泛型允许编写更具通用性的基类,不必针对每种数据类型重复实现类似功能,增加了代码的重用性.
泛型使得类型参数在类定义中显式化,这样可以帮助开发者更清楚地了解类或函数的预期类型,减少类型推断的复杂度,提升可读性.
现代 Python 开发中,使用类型提示(type hinting)已经成为一种最佳实践。泛型定义能够更好地与类型检查工具(如 mypy、pyright 等)集成,帮助在编写代码时发现潜在的类型错误.
使用泛型定义基类可以让类的功能更通用,从而在不修改类代码的情况下,通过类型参数化来实现不同的数据处理逻辑.
。
以上这些优势使得在大型项目或库开发中使用泛型变得尤为重要,尤其是在设计通用数据结构、工具类或框架时.
泛型定义,我们声明一个类型,如下所示.
ModelType = TypeVar("ModelType") # 定义泛型基类
然后就可以根据需要采用泛型类型了,如下是窗体基类的定义,采用一个泛型的类型来定义业务模块的子类DTO对象,从而使得该父类很多接口都具有很好的类型化定义.
# 创建泛型基类 BaseFrameList,并继承 wx.Panel class BaseFrameList(wx.Panel, Generic[ModelType]):
而对于业务模块的子类,如其中业务列表界面的子类定义如下所示.
# 继承BaseFrameList类,并传入实体类SystemTypeInfo,作为泛型类型 class FrmSystemType(BaseFrameList[SystemTypeDto]):
这样我们构建的列表界面父子类的关系如下 所示,其中包括两个业务模块的列表界面:系统类型定义,客户信息.
例如我们以客户列表界面的子类代码进行分析,如下所示。我们只需要传入所需的一些字段显示及中文解析,并传入相关的DTO对象,如下代码所示.
# 继承BaseFrameList类,并传入实体类CustomerInfo,作为泛型类型 class FrmCustomer(BaseFrameList[CustomerDto]): """客户信息""" # 显示的字段名称,逗号分隔 display_columns = "id,name,age,creator,createtime" # 列名映射(字段名到显示名的映射) column_mapping = { "id": "编号", "name": "姓名", "age": "年龄", "creator": "创建人", "createtime": "创建时间", } def __init__(self, parent): # 初始化基类信息 super().__init__( parent, model=CustomerDto, display_columns=self.display_columns, column_mapping=self.column_mapping )
这些内容肯定是必须的,另外,如果我们需要自定义列表界面中单元格列的宽度,也可以指定宽度的字典参照,不指定则使用默认宽度即可(在基类定义默认宽度,如为150像素).
例如,我在系统类型定义中就包含了列表宽度的字典参考,代码如下所示.
# 继承BaseFrameList类,并传入实体类SystemTypeInfo,作为泛型类型 class FrmSystemType(BaseFrameList[SystemTypeDto]): """系统类型定义""" # 显示的字段名称,逗号分隔 display_columns = "id,name,customid,authorize,note" # 列名映射(字段名到显示名的映射) column_mapping = { "id": "系统标识", "name": "系统名称", "customid": "客户编码", "authorize": "授权编码", "note": "备注", } # 表格显示的列宽 column_widths = {"id": 150, "name": 250, "customid": 100, "authorize": 100} def __init__(self, parent): # 初始化基类信息 super().__init__( parent, model=SystemTypeDto, display_columns=self.display_columns, column_mapping=self.column_mapping, column_widths=self.column_widths, use_left_panel=False, )
。
而对于子类查询条件的内容,我们前面说它是动态不同的,因此需要子类来具体实现.
下面这个是客户信息的查询内容,我们只需要添加对应的标签和输入控件即可,不需要理会布局的处理,默认的FlexGridSizer为4*2=8列,每列间隔5px.
下面是客户信息的列表界面,重写父类函数的实现代码 。
def CreateConditions(self, pane: wx.Window) -> List[wx.Window]: """创建折叠面板中的查询条件输入框控件""" # 创建控件,不用管布局,交给CreateConditionsWithSizer控制逻辑 # 默认的FlexGridSizer为4*2=8列,每列间隔5px lblName = wx.StaticText(pane, -1, "姓名:") self.txtName = wx.TextCtrl(pane, -1, size=(150, -1)) lblAge = wx.StaticText(pane, -1, "年龄:") self.txtAge = ctrl.MyNumericRange(pane, -1, size=(150, -1)) return [lblName, self.txtName, lblAge, self.txtAge]
如果有时候需要重新定义布局,那么可以重写它上一级包含布局的函数即可实现更高维度的定制处理.
如对于系统类型的列表界面,如下所示 。
为了更好介绍对于面板布局的控制,我重写其上一级的函数,包含FlexGridSizer的定义信息,这里我们的代码如下所示.
def CreateConditionsWithSizer(self, pane: wx.Window): """子类可重写该方法,创建折叠面板中的查询条件,包括布局FlexGridSizer""" # 先创建控件 lblSystemType = wx.StaticText(pane, -1, "系统标识:") self.txtSystemType = wx.TextCtrl(pane, -1, "", size=(150, -1)) lblName = wx.StaticText(pane, -1, "系统名称:") self.txtName = wx.TextCtrl(pane, -1, "", size=(150, -1)) lblCustomCode = wx.StaticText(pane, -1, "客户编码:") self.txtCustomCode = wx.TextCtrl(pane, -1, "", size=(150, -1)) lblAuthCode = wx.StaticText(pane, -1, "授权编码:") self.txtAuthCode = wx.TextCtrl(pane, -1, "", size=(150, -1)) # 增加条件面板 input_sizer = wx.FlexGridSizer(cols=4 * 2, hgap=5, vgap=5) # 统一处理查询条件控件的添加,使用默认的布局方式 list = [lblSystemType, self.txtSystemType, lblName, self.txtName, lblCustomCode, self.txtCustomCode, lblAuthCode, self.txtAuthCode] for i in range(len(list)): input_sizer.Add(list[i], 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5) # input_sizer.AddGrowableCol(1) # input_sizer.Add((5, 5)) return input_sizer
。
而对于子类的编辑查看对话框,我们通过触发按钮进行弹出,或者右键的菜单中弹出,都是同样的逻辑,不过就是界面内容不同,我们可以让子类进行实现即可.
子类对于新增编辑的界面实现代码如下所示,其中Add和OnEditById都是父类的空函数,由子类来具体实现即可(覆盖重写).
def OnAdd(self, event: wx.Event) -> None: """子类重写-打开新增对话框""" dlg = FrmSystemTypeEdit(self) if dlg.ShowModal() == wx.ID_OK: # 新增成功,刷新表格 self.update_grid() dlg.Destroy() def OnEditById(self, entity_id: Any | str): """子类重写-根据主键值打开编辑对话框""" dlg = FrmSystemTypeEdit(self, entity_id) if dlg.ShowModal() == wx.ID_OK: # 更新grid列表数据 self.update_grid() dlg.Destroy()
其他处理,如删除记录、导入、导出的处理,大同小异,从变化中找到不变的逻辑交给父类处理,子类负责最原始变化的内容即可.
当然对于一些复杂的列表界面,可能还需要考虑左侧放置一些树列表以便快速的选择不同分类的数据,如下Winform上的界面.
这个界面的内容,左侧就是折叠的两个树列表:机构列表、角色列表,以便方便选择用户信息.
那么对于这样的效果,我们在基类窗体中是否可以抽象出来,答案当然是可以的,还记得我们前面《使用wxpython开发跨平台桌面应用,动态工具的创建处理 》介绍过的工具栏的时候,使用了Manager类的实现效果.
不过这个是主窗体级别的,我们需要为具体的业务列表界面定义一个类似的效果.
我们在父类窗体中定义一个开关变量,用来开启或者关闭左侧树列表面板的,如下代码所示.
这样构建树列表就交给函数 create_tree_panels 实现即可,它会构建一到多个的树列表,父界面窗体负责整合它们显示即可.
如子类定义重写创建树列表的函数,如下代码所示.
def create_tree_panels(self) -> dict[str, wx.Panel]: """子类重写该方法,创建左侧树列表面板-可以多个树列表""" dict = {} # 示例代码 for key in ["机构列表", "角色列表"]: tree_panel = wx.Panel(self) tree_sizer = wx.BoxSizer(wx.VERTICAL) tree = CT.CustomTreeCtrl(tree_panel, style=wx.TR_DEFAULT_STYLE) self._populate_tree(tree) tree_sizer.Add(tree, 1, wx.EXPAND) tree_panel.SetSizer(tree_sizer) dict[key] = tree_panel return dict
那么界面效果会获得如下所示.
我们根据需要实现具体的树数据显示即可。 。
以上就是我对于界面的剖析和逐步的抽象处理,把主要的逻辑提取到父类中去,变化的小部分内容,交给子类差别实现即可,减少代码,提高效率.
最后此篇关于使用wxpython开发跨平台桌面应用,基类列表窗体的抽象封装处理的文章就讲到这里了,如果你想了解更多关于使用wxpython开发跨平台桌面应用,基类列表窗体的抽象封装处理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
这显然有可能导致一场激烈的 war ,但无论如何,我试一试……(目前)还没有任何明确的答案。 在我的一台机器上,我确实被切换/升级到 Matlab 2012b。这是一个漂亮的新桌面,好吧。但出于很多原
当我的 Docker 容器启动时,我收到以下通知: Docker Desktop has detected that you shared a Windows file into a WSL 2 co
我希望能够(从服务器)连接到远程 PC 并能够访问其文件。我正在尝试使用 PHP 或 JavaScript 来完成此操作。 所以我想知道 1) 是否可能以及 2) 如何做到。 有人有任何示例/解决方案
我想使用 DirectX 为 Windows 7 制作动画桌面背景。我正在使用 C#、SlimDX 和几个 Windows API 函数的 P/Invoke 导入。我对 native Windows
是否可以为 Mac 开发动态桌面?我所说的“动态”是指其图像采用系统参数(例如时间和作业信息)并使用此信息来更新图像的桌面。有关图像状态的信息也将在 session 之间保留。我不是在谈论电影或随机但
我正在 LibGDX 中构建一个仅限桌面的应用程序。该游戏内置了一个 map 编辑器,您可以切换到并更改游戏 map 。我想添加一个功能,如果用户单击关闭窗口并且有未保存的编辑,它会提示您是否要在关闭
有没有像样的Windows桌面JSON lines (JSONL)格式查看器? 这种格式也称为: 行分隔的 JSON (LDJSON) 换行符分隔的 JSON (NDJSON) 我正在寻找至少能够从
我有一个UITableView,它在单元格中显示大量图像,并且我对滚动性能并不满意。我的 UITableView 类似于 iPhone 上的照片应用程序。有谁知道为什么 iphone 照片应用程序滚动
let img1 = document.createElement('img'); img1.setAttribute('src', 'https://caniuse.com/img/browsers
我在同一窗体上有两个不同的网格控件。它们共享相同的上下文菜单。当我选择上下文菜单项时,我无法确定哪个控件是所有者。 最佳答案 ContextMenuStrip 类的 SourceControl 属性将
我已经安装了 Docker Desktop ( version : 2.3.0.4 ) 并启用了 Kubernetes . 我部署了几个 PODS,一切正常,从昨天开始,我遇到了下面提到的一个奇怪的问
我正在制作需要实现TableView的应用程序。 我想将背景图像应用到桌面 View 。 谁能帮我解决这个问题。我正在使用下面的代码来创建 TableView Titanium.UI.setBackg
我在同一窗体上有两个不同的网格控件。它们共享相同的上下文菜单。当我选择上下文菜单项时,我无法确定哪个控件是所有者。 最佳答案 ContextMenuStrip 类的 SourceControl 属性将
您能建议一些库在我的桌面 Java 应用程序中创建雷达图吗? 谢谢 最佳答案 似乎JFreeChart提供了SpiderWebPlot 。 images for which看起来像雷达图。 关于jav
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Not possible to launch a file on a network using Java Desk
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我想知道是否可以(使用JAVA)识别用于发出请求的计算机类型,例如:服务器、台式机、PDA(平板电脑、手机等)? 谢谢! 最佳答案 取决于您使用什么来接受请求。对于 http 请求,信息位于请求 he
我添加了一个事件处理程序,用于滚动到我的桌面 View ,但它仅在我使用滚轮滚动时才起作用,但我也需要它在您单击并拖动滚动条时起作用。任何想法有什么问题吗?我尝试使用不同的方法来处理该事件,但没有一个
我想开始开发桌面 Java 应用程序,并且我想知道 Java 社区使用什么。 我从 Swing 开始,但发现它非常初级。 我习惯于在 Visual Studio 2010 中使用 .net c# WP
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
我是一名优秀的程序员,十分优秀!