WxPython跨平台开发框架之主从表展示和录入的界面处理--产品报价单和明细记录的处理
<p>我们在前面随笔《Vue3+ElementPlus的BS端主从表的快速开发》了解了Vue3+ElementPlus的BS端主从表的实现,了解了大概的设计和界面设计方式,我们现在切换一下,看看如何结合FastAPI+WxPython实现主从表界面的展示和编辑处理的。</p><p>FastAPI的后端采用控制器基类继承方式提供标准化接口,SqlALchemy提供的数据ORM管理,相关代码通过代码生成工具快速生成,包括后端的API接口定义类,SqlALchemy模型类、DTO对象类,以及前端的界面生成等工作。本篇随笔主要介绍WxPython跨平台开发框架之主从表展示和录入的界面处理--产品报价单和明细记录的处理。</p>
<h3>1、FastAPI实现主从表数据接口和SqlAlchemy的数据处理</h3>
<p>WxPython跨平台开发框架全部采用Python语言进行开发,包括后端的内容,采用 基于SqlAlchemy+Pydantic+FastApi 的后端框架,FastAPI启动后,进入Swagger页面如下所示,列出每个业务表的相关接口。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202409/8867-20240924130101025-2019486625.png" alt="" width="905" height="596" class="medium-zoom-image" loading="lazy"></p>
<p>以上就是常规化的接口,包括单个获取、ID存在、条件查询、分页查询、数量查询、增加、删除、更新等标准化接口,这些基础类接口一般封装在API的控制器基类中。</p>
<p>该后端接口采用统一的接口协议,标准协议如下所示。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">success</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">result</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:T ,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">targetUrl</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">UnAuthorizedRequest</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">errorInfo</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">code</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">message</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">details</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
}</span></pre>
</div>
<p>常规化的接口是结合泛型的方式,这样定义可以很好的抽象不同的业务类接口到基类控制器中,如下是FastApi 后端的基类控制器定义。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016094657253-1511663754.png" alt="image" width="989" height="1016" loading="lazy"></p>
<p> 有了上面基类定义好的常规化接口,子类只需要继承基类控制器即可获得强大的功能接口了。</p>
<p>一般API控制器的子类,只需要继承基类就可以了,额外增加的接口按常规化的设计函数即可,可以参考基类的做法来写各种(GET、PUT、DELETE、POST)的处理函数。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016095108239-1440935466.png" alt="image" width="989" height="1030" loading="lazy"></p>
<p>我们来看看对于产品报价单和明细记录的处理,这两个代表不同的业务表,我们可以分开管理,通过约束他们的记录关系实现主从表弹性化的管理。</p>
<p>如对于主表,我们在基类接口外定义多两个函数,主要就是删除主表的时候,同时移除明细记录的关联操作。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> fastapi <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> APIRouter, Depends, HTTPException, Query, Request, Path, Body
</span><span style="color: rgba(0, 0, 0, 1)"><span style="color: rgba(0, 0, 255, 1)">..................<br></span></span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 创建路由,用于处理自定义接口</span>
router =<span style="color: rgba(0, 0, 0, 1)"> APIRouter()
@router.get(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">byorderno/{orderno}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
response_model</span>=AjaxResponse,
summary</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">根据报价单编号获取对象信息</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
dependencies</span>=<span style="color: rgba(0, 0, 0, 1)">,
)
async </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> find_by_orderno(
orderno: Annotated,
request: Request,
db: AsyncSession </span>=<span style="color: rgba(0, 0, 0, 1)"> Depends(get_db),
):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> ip = await get_request_ip(request)</span>
item = await quotation_crud.get_by_column(db, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">handno</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, orderno)
item </span>= QuotationDto.model_validate(item) <span style="color: rgba(0, 0, 255, 1)">if</span> item <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> None
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse(item)
@router.delete(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">quotation-related/{id}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
response_model</span>=AjaxResponse,
summary</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">删除报价单及明细信息</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
dependencies</span>=<span style="color: rgba(0, 0, 0, 1)">,
)
async </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> delete_quotation_related(
id: Annotated,
request: Request,
db: AsyncSession </span>=<span style="color: rgba(0, 0, 0, 1)"> Depends(get_db),
):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> ip = await get_request_ip(request)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">获取记录信息</span>
item =<span style="color: rgba(0, 0, 0, 1)"> await quotation_crud.get(db, id)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> item:
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse(False)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 删除相关的明细记录</span>
res = await quotationdetail_crud.delete_by_column(db, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">orderno</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, item.handno)
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> res:
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 再删除报价单</span>
<span style="color: rgba(0, 0, 0, 1)"> await quotation_crud.delete_byid(db, id)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse(res)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 使用基类控制器,可以继承常规CRUD的接口,并自动生成路由,依赖注入,数据库连接等功能 ——构建方式2</span>
controller =<span style="color: rgba(0, 0, 0, 1)"> BaseController(
quotation_crud,
pagedto_class</span>=<span style="color: rgba(0, 0, 0, 1)">QuotationPageDto,
dto_class</span>=<span style="color: rgba(0, 0, 0, 1)">QuotationDto,
router</span>=<span style="color: rgba(0, 0, 0, 1)">router,
)
controller.init_router()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 初始化常规CRUD等接口的路由</span></pre>
</div>
<p>而报价单明细业务控制器,主要需要根据报价单号(订单号)获取明细的接口</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> fastapi <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> APIRouter, Depends, HTTPException, Query, Request, Path, Body
</span><span style="color: rgba(0, 0, 255, 1)">from</span> typing <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Type, TypeVar, Generic, List, Dict, Any, Optional, Annotated
</span><span style="color: rgba(0, 0, 255, 1)">from</span> datetime <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> datetime
</span><span style="color: rgba(0, 0, 255, 1)">from</span> sqlalchemy.ext.asyncio <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> AsyncSession
</span><span style="color: rgba(0, 0, 255, 1)">from</span> schemas.base <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse, ErrorInfo, ListResult, PagedResult
</span><span style="color: rgba(0, 0, 255, 1)">from</span> api.base_controller <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> BaseController
</span><span style="color: rgba(0, 0, 255, 1)">from</span> db.session_async <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> get_db
</span><span style="color: rgba(0, 0, 255, 1)">from</span> common.jwt <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> DependsJwtAuth
</span><span style="color: rgba(0, 0, 255, 1)">from</span> models.quotationdetail <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> QuotationDetail
</span><span style="color: rgba(0, 0, 255, 1)">from</span> schemas.quotationdetail <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> QuotationDetailDto, QuotationDetailPageDto
</span><span style="color: rgba(0, 0, 255, 1)">from</span> crud.quotationdetail <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> quotationdetail as quotationdetail_crud
</span><span style="color: rgba(0, 0, 255, 1)">from</span> crud.operationlog <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> operationlog as operationlog_crud
</span><span style="color: rgba(0, 0, 255, 1)">from</span> utils.request_parse <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> get_request_ip
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 创建路由,用于处理自定义接口</span>
router =<span style="color: rgba(0, 0, 0, 1)"> APIRouter()
@router.get(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/by-orderno</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
response_model</span>=AjaxResponse |<span style="color: rgba(0, 0, 0, 1)"> None],
summary</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">根据订单编号获取记录</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
dependencies</span>=<span style="color: rgba(0, 0, 0, 1)">,
)
async </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> get_by_orderno(
orderno: Annotated,
request: Request,
db: AsyncSession </span>=<span style="color: rgba(0, 0, 0, 1)"> Depends(get_db),
):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> ip = await get_request_ip(request)</span>
items =<span style="color: rgba(0, 0, 0, 1)"> await quotationdetail_crud.get_by_orderno(db, orderno)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> print(len(items))</span>
items =
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse(items)
@router.delete(
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/by-orderno/{orderno}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
response_model</span>=AjaxResponse,
summary</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">根据订单编号删除所有明细记录</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
dependencies</span>=<span style="color: rgba(0, 0, 0, 1)">,
)
async </span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> delete_by_orderno(
orderno: Annotated,
request: Request,
db: AsyncSession </span>=<span style="color: rgba(0, 0, 0, 1)"> Depends(get_db),
):
res </span>= await quotationdetail_crud.delete_by_attributes(db, QuotationDetail.orderno ==<span style="color: rgba(0, 0, 0, 1)"> orderno)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> AjaxResponse(res)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 使用基类控制器,可以继承常规CRUD的接口,并自动生成路由,依赖注入,数据库连接等功能 </span>
controller =<span style="color: rgba(0, 0, 0, 1)"> BaseController(
quotationdetail_crud,
pagedto_class</span>=<span style="color: rgba(0, 0, 0, 1)">QuotationDetailPageDto,
dto_class</span>=<span style="color: rgba(0, 0, 0, 1)">QuotationDetailDto,
router</span>=<span style="color: rgba(0, 0, 0, 1)">router,
)
controller.init_router()</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 初始化常规CRUD等接口的路由</span></pre>
</div>
<p> </p>
<p>由于基类控制器接口的标准化,我们根据框架后端的接口进行前端API调用类的封装处理,从而实现业务基类调用接口的统一封装,简化代码。这样增删改查等处理的接口都可以抽象到BaseApi里面了。</p>
<p>如对于权限模块,我们涉及到的用户管理、机构管理、角色管理、菜单管理、功能管理、操作日志、登录日志等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。</p>
<p><img src="https://img2020.cnblogs.com/blog/8867/202007/8867-20200713152737929-890201160.png" alt="" class="medium-zoom-image" loading="lazy"></p>
<p> </p>
<h3>2、基于SqlAlchemy实现的业务模型</h3>
<p>FastAPI负责提供数据的API接口,底层的数据处理,通过SqlAlchemy + MongoDB 实现多种数据库的数据管理,如对于MySQL、Postgresql、SQLite、Oracle、MongoDB等进行接入和数据交换处理。</p>
<p>对于常规的业务表,我们采用SqlAlchemy实现数据库的ORM管理的,SqlAlchemy也是Python领域中非常强大的ORM管理模块之一, 它让你用 <strong data-start="97" data-end="116">Python 对象来操作数据库</strong>,而不是手写 SQL 语句。</p>
<p>一般我们先定义好模型的基类,提供简单的封装</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016101144230-1883745931.png" alt="image" width="632" height="426" loading="lazy"></p>
<p> 然后在业务类里面继承它即可</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016100647277-339660946.png" alt="image" width="1111" height="610" loading="lazy"></p>
<p> 报价单的明细表也是类似的</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016101327015-2048136472.png" alt="image" width="1101" height="637" loading="lazy"></p>
<p>这些模型类和对应接口的DTO类只需要在代码生成工具中进行一键生成就可以了,不用编写。</p>
<p> 在代码生成工具 Database2Sharp 打开数据库列表后,右键菜单可以选择生成对应的Python+FastApi后端项目,如下界面所示。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202412/8867-20241203105942996-1920544172.png" alt="" width="1028" height="663" class="medium-zoom-image" loading="lazy"></p>
<p>选中相关的表后,一键可以生成各层的类文件,其中包括最为繁琐的Model映射类信息。如下是生成的相关类的界面效果。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202409/8867-20240924132826926-1882542884.png" alt="" width="976" height="719" class="medium-zoom-image" loading="lazy"></p>
<p> </p>
<h3>2、WxPthon实现基于Python桌面端主从表的数据处理</h3>
<p>我们知道,一般对于单表来说,业务和界面会相对比较简单,如下面的界面效果,在Windows下客户信息的列表管理和数据编辑界面如下所示。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202412/8867-20241203120302214-463232027.png" alt="" width="746" height="524" class="medium-zoom-image" loading="lazy"></p>
<p> </p>
<p>而对于主从表,一般除了主业务表外,会关联一个到多个的明细表,对于报价单来说,就只有一个明细表,如下所示是具体的界面列表展示。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251015161712585-317398086.png" alt="image" width="981" height="665" loading="lazy"></p>
<p>对于列表的主从表关联关系,没有太多好说的,就是增加了一个明细表的处理展示</p>
<p>对于主从表编辑界面来说,就需要复杂处理一些,在表格需要直接编辑录入并保存明细的操作处理,如下是主从表的编辑界面的实现效果。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251015161911167-1840409017.png" alt="image" width="822" height="589" loading="lazy"></p>
<p>其主要就是在第一次创建的时候,对表格数据类进行设置</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016104543810-1687839480.png" alt="image" width="870" height="832" loading="lazy"></p>
<p>表格的数据直接录入,一般不是仅仅的通过文本框的录入,一般录入有选择表的记录,下拉类表、复选框、图像、数值、颜色等等特殊的录入的。</p>
<p> 如自定义数据列表选择界面,我通过定义一个产品的数据列表展示供选择,单击产品编码处,弹出一个选择框进行选择。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251015162218443-1590695835.png" alt="image" width="867" height="621" loading="lazy"></p>
<p>为了实现对表格数据单元格的单击监控,我们绑定了对应的事件。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(255, 0, 0, 1)"><strong>AsyncBind</strong></span>(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.on_cell_left_click, self.sub_grid)</pre>
</div>
<p>然后对事件进行实现即可。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016105037344-164921934.png" alt="image" width="899" height="664" loading="lazy"></p>
<p> 下拉列表则是通过绑定固定列表,或者字典类型的方式实现字典下拉列表选择</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251015162347832-235980690.png" alt="image" width="869" height="622" loading="lazy"></p>
<p>初始化字典列表很容易,如下代码所示。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251016104356263-1431900218.png" alt="image" width="759" height="286" loading="lazy"></p>
<p> 其他案例可以参考测试效果,支持多种数据输入处理,测试界面效果如下所示。</p>
<p><img src="https://img2024.cnblogs.com/blog/8867/202510/8867-20251015162715390-1980915131.png" alt="image" width="1099" height="240" loading="lazy"></p>
<p> </p>
<p>以上就是对于WxPython应用,结合前后端的处理,实现了主从表展示和录入的界面处理--产品报价单和明细记录的处理。</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="border-right-color: #cccccc; border-right-width: 1px; border-right-style: solid; padding-right: 5px; border-top-color: #cccccc; border-top-width: 1px; border-top-style: solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left-color: #cccccc; border-left-width: 1px; border-left-style: solid; width: 98%; padding-top: 4px; border-bottom-color: #cccccc; border-bottom-width: 1px; border-bottom-style: solid; background-color: #eeeeee;">
<img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top" alt>
<span style="color: #000000"><span class="Apple-tab-span" style="white-space: pre"></span>
专注于代码生成工具、.Net/Python 框架架构及软件开发,以及各种Vue.js的前端技术应用。著有Winform开发框架/混合式开发框架、微信开发框架、Bootstrap开发框架、ABP开发框架、SqlSugar开发框架、Python开发框架等框架产品。
<br> 转载请注明出处:撰写人:伍华聪 http://www.iqidi.com <br> </span></div><br><br>
来源:https://www.cnblogs.com/wuhuacong/p/19143692
頁:
[1]