使用wxPython开发FGCC数据库查看器的完整指南

Written by

in

文章目录
  • 目录
    • 一、背景
      • 1.1 问题的提出
      • 1.2 技术选型
    • 二、目标
      • 2.1 核心功能需求
      • 2.2 用户体验目标
    • 三、方法
      • 3.1 架构设计
      • 3.2 核心技术方案
    • 四、实现过程
      • 4.1 项目初始化
      • 4.2 主窗口框架构建
      • 4.3 用户界面构建
        • 4.3.1 文件选择区域
        • 4.3.2 分割窗口设计
      • 4.4 核心功能实现
        • 4.4.1 文件选择与解析
        • 4.4.2 ZIP文件提取
        • 4.4.3 数据库表加载
        • 4.4.4 表数据动态展示
        • 4.4.5 数据库导出功能
        • 4.4.6 资源清理
    • 五、运行结果
      • 5.1 程序启动界面
        • 5.2 加载FGCC文件
          • 5.3 查看表数据
            • 5.4 导出数据库

            在企业级应用开发中,Forguncy是一款流行的低代码开发平台。它将应用程序打包为.fgcc格式的文件,这种文件本质上是一个ZIP压缩包,内部包含了应用的各种资源,其中最重要的是ForguncyDB.sqlite3数据库文件。

            然而,在实际工作中,开发人员经常面临以下痛点:
            C:pythoncodenewfgcc_db_viewer.py

            • 数据检查困难:无法直接查看FGCC文件中的数据库内容
            • 操作繁琐:需要手动解压、查找数据库文件、使用第三方工具打开
            • 效率低下:频繁的数据库检查工作耗费大量时间
            • 工具分散:需要在多个软件之间切换(解压工具、数据库查看器等)

            为了解决这些问题,我们选择了以下技术栈:

            • wxPython:成熟的跨平台GUI框架,提供原生外观
            • SQLite3:Python内置模块,无需额外安装
            • zipfile:Python标准库,处理ZIP格式文件

            我们要开发一个集成化的工具,实现以下功能:

            1. 文件选择:通过图形界面选择FGCC文件
            2. 自动解析:自动提取ZIP中的数据库文件
            3. 数据库连接:自动连接SQLite数据库
            4. 表结构展示:列出所有数据库表名
            5. 数据查看:双击表名即可查看完整数据
            6. 数据导出:支持将数据库文件导出到指定位置

            • 一站式操作:所有功能在一个窗口完成
            • 直观易用:符合用户操作习惯的界面设计
            • 实时反馈:每个操作都有状态提示
            • 错误处理:友好的错误提示和异常处理

            采用单窗口多面板的设计模式:

            ┌─────────────────────────────────────────┐
            │  文件选择区 [选择] [导出]                │
            ├──────────────┬──────────────────────────┤
            │  表列表面板  │   数据展示面板           │
            │  (ListBox)   │   (Grid)                 │
            │              │                          │
            │  - Table1    │   Col1  Col2  Col3       │
            │  - Table2    │   data  data  data       │
            │  - Table3    │   data  data  data       │
            └──────────────┴──────────────────────────┘
            │         状态栏                           │
            └─────────────────────────────────────────┘
            

            文件处理流程

            1. 用户选择.fgcc文件
            2. 使用zipfile模块打开ZIP文件
            3. 搜索并提取ForguncyDB.sqlite3
            4. 保存到临时目录
            5. 建立SQLite连接

            数据展示方案

            • 使用wx.ListBox展示表名列表
            • 使用wx.grid.Grid展示表数据
            • 通过wx.SplitterWindow实现可调整的分割布局

            首先导入必要的模块:

            import wx
            import wx.grid
            import zipfile
            import sqlite3
            import os
            import tempfile
            from pathlib import Path
            

            这里需要特别注意:wx.grid必须单独导入,否则会出现AttributeError错误。

            创建继承自wx.Frame的主窗口类:

            class DatabaseViewerFrame(wx.Frame):
                def __init__(self):
                    super().__init__(parent=None, title='FGCC数据库查看器', 
                                    size=(1000, 600))
                    
                    self.db_path = None      # 数据库文件路径
                    self.conn = None         # 数据库连接对象
                    self.temp_dir = tempfile.mkdtemp()  # 临时目录
                    
                    self.init_ui()
                    self.Bind(wx.EVT_CLOSE, self.on_close)
                    self.Centre()
                    self.Show()
            

            设计要点

            • 使用临时目录存储提取的数据库文件
            • 绑定关闭事件以确保资源清理
            • Centre()方法使窗口居中显示

            file_sizer = wx.BoxSizer(wx.HORIZONTAL)
            self.file_text = wx.TextCtrl(panel, style=wx.TE_READONLY)
            select_btn = wx.Button(panel, label='选择FGCC文件')
            select_btn.Bind(wx.EVT_BUTTON, self.on_select_file)
            
            self.export_btn = wx.Button(panel, label='导出数据库')
            self.export_btn.Enable(False)  # 初始禁用
            self.export_btn.Bind(wx.EVT_BUTTON, self.on_export_database)
            

            关键技术

            • wx.TE_READONLY:文本框只读,防止手动修改
            • Enable(False):按钮初始禁用,加载数据库后才启用
            • 使用BoxSizer实现水平布局

            splitter = wx.SplitterWindow(panel)
            
            # 左侧面板:表列表
            left_panel = wx.Panel(splitter)
            self.table_list = wx.ListBox(left_panel)
            self.table_list.Bind(wx.EVT_LISTBOX_DCLICK, self.on_table_double_click)
            
            # 右侧面板:数据网格
            right_panel = wx.Panel(splitter)
            self.data_grid = wx.grid.Grid(right_panel)
            self.data_grid.CreateGrid(0, 0)
            self.data_grid.EnableEditing(False)
            
            # 设置分割比例
            splitter.SplitVertically(left_panel, right_panel)
            splitter.SetSashPosition(250)
            splitter.SetMinimumPaneSize(200)
            

            亮点设计

            • SplitterWindow允许用户拖动调整左右面板大小
            • 左侧面板固定250像素宽度,但可调整
            • 数据网格禁用编辑,保护数据安全
            • 双击事件绑定实现直观的交互

            def on_select_file(self, event):
                with wx.FileDialog(self, "选择FGCC文件",
                                  wildcard="FGCC files (*.fgcc)|*.fgcc",
                                  style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as dlg:
                    
                    if dlg.ShowModal() == wx.ID_OK:
                        fgcc_path = dlg.GetPath()
                        self.file_text.SetValue(fgcc_path)
                        self.extract_and_connect(fgcc_path)
            

            技术细节

            • 使用上下文管理器自动管理对话框资源
            • wildcard参数过滤文件类型
            • wx.FD_FILE_MUST_EXIST确保文件存在

            def extract_and_connect(self, fgcc_path):
                try:
                    # 关闭之前的连接
                    if self.conn:
                        self.conn.close()
                    
                    self.status_bar.SetStatusText('正在提取数据库文件...')
                    
                    with zipfile.ZipFile(fgcc_path, 'r') as zip_ref:
                        # 智能查找数据库文件
                        db_file = None
                        for name in zip_ref.namelist():
                            if 'ForguncyDB.sqlite3' in name:
                                db_file = name
                                break
                        
                        if not db_file:
                            wx.MessageBox('未找到ForguncyDB.sqlite3文件', 
                                        '错误', wx.OK | wx.ICON_ERROR)
                            return
                        
                        # 提取到临时目录
                        zip_ref.extract(db_file, self.temp_dir)
                        self.db_path = os.path.join(self.temp_dir, db_file)
                    
                    # 连接数据库
                    self.conn = sqlite3.connect(self.db_path)
                    self.load_tables()
                    self.export_btn.Enable(True)
                    
                except Exception as e:
                    wx.MessageBox(f'处理文件时出错: {str(e)}', 
                                 '错误', wx.OK | wx.ICON_ERROR)
            

            关键实现

            • 遍历ZIP文件列表查找目标文件(支持不同路径结构)
            • 使用临时目录避免污染用户文件系统
            • 完善的异常处理和用户提示
            • 成功后启用导出按钮

            def load_tables(self):
                try:
                    cursor = self.conn.cursor()
                    cursor.execute(
                        "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
                    )
                    tables = cursor.fetchall()
                    
                    self.table_list.Clear()
                    for table in tables:
                        self.table_list.Append(table[0])
                    
                    # 清空数据网格
                    if self.data_grid.GetNumberRows() > 0:
                        self.data_grid.DeleteRows(0, self.data_grid.GetNumberRows())
                    if self.data_grid.GetNumberCols() > 0:
                        self.data_grid.DeleteCols(0, self.data_grid.GetNumberCols())
                        
                except Exception as e:
                    wx.MessageBox(f'加载表列表时出错: {str(e)}', 
                                 '错误', wx.OK | wx.ICON_ERROR)
            

            SQL技巧

            • 查询sqlite_master系统表获取所有表名
            • WHERE type='table'过滤掉视图和索引
            • ORDER BY name按字母顺序排序

            def load_table_data(self, table_name):
                try:
                    cursor = self.conn.cursor()
                    cursor.execute(f'SELECT * FROM "{table_name}"')
                    
                    rows = cursor.fetchall()
                    columns = [description[0] for description in cursor.description]
                    
                    # 动态创建网格
                    if self.data_grid.GetNumberRows() > 0:
                        self.data_grid.DeleteRows(0, self.data_grid.GetNumberRows())
                    if self.data_grid.GetNumberCols() > 0:
                        self.data_grid.DeleteCols(0, self.data_grid.GetNumberCols())
                    
                    # 设置列
                    if len(columns) > 0:
                        self.data_grid.AppendCols(len(columns))
                        for i, col in enumerate(columns):
                            self.data_grid.SetColLabelValue(i, col)
                    
                    # 填充数据
                    if len(rows) > 0:
                        self.data_grid.AppendRows(len(rows))
                        for i, row in enumerate(rows):
                            for j, value in enumerate(row):
                                self.data_grid.SetCellValue(
                                    i, j, str(value) if value is not None else ''
                                )
                    
                    # 自动调整列宽
                    self.data_grid.AutoSizeColumns()
                    
                    self.data_label.SetLabel(
                        f'记录数据: {table_name} (共 {len(rows)} 条记录)'
                    )
                    
                except Exception as e:
                    wx.MessageBox(f'加载表数据时出错: {str(e)}', 
                                 '错误', wx.OK | wx.ICON_ERROR)
            

            实现亮点

            • 使用双引号包裹表名,支持包含特殊字符的表名
            • 通过cursor.description获取列名
            • 动态创建网格,适应不同表结构
            • AutoSizeColumns()智能调整列宽
            • NULL值显示为空字符串,提升可读性

            def on_export_database(self, event):
                if not self.db_path or not os.path.exists(self.db_path):
                    wx.MessageBox('没有可导出的数据库文件', 
                                 '错误', wx.OK | wx.ICON_ERROR)
                    return
                
                with wx.FileDialog(self, "导出数据库文件",
                                  defaultFile="ForguncyDB.sqlite3",
                                  wildcard="SQLite database (*.sqlite3)|*.sqlite3|All files (*.*)|*.*",
                                  style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) as dlg:
                    
                    if dlg.ShowModal() == wx.ID_OK:
                        export_path = dlg.GetPath()
                        try:
                            import shutil
                            shutil.copy2(self.db_path, export_path)
                            
                            wx.MessageBox(f'数据库已成功导出到:n{export_path}', 
                                        '成功', wx.OK | wx.ICON_INFORMATION)
                            
                        except Exception as e:
                            wx.MessageBox(f'导出数据库时出错: {str(e)}', 
                                         '错误', wx.OK | wx.ICON_ERROR)
            

            设计考虑

            • wx.FD_OVERWRITE_PROMPT自动提示覆盖确认
            • shutil.copy2保留文件元数据
            • 导出成功后显示完整路径,方便用户定位

            def on_close(self, event):
                # 关闭数据库连接
                if self.conn:
                    self.conn.close()
                
                # 删除临时文件
                try:
                    import shutil
                    if os.path.exists(self.temp_dir):
                        shutil.rmtree(self.temp_dir)
                except:
                    pass
                
                self.Destroy()
            

            最佳实践

            • 程序退出前清理所有资源
            • 删除临时文件避免磁盘占用
            • 使用try-except确保即使清理失败也能正常退出

            启动程序后,呈现简洁的主界面:

            • 顶部显示文件选择区域
            • 导出按钮处于禁用状态
            • 左右分割面板为空
            • 状态栏提示"请选择FGCC文件"

            点击"选择FGCC文件"按钮后:

            1. 弹出文件选择对话框,过滤.fgcc格式
            2. 选择文件后自动开始解析
            3. 状态栏显示"正在提取数据库文件…"
            4. 成功后状态栏显示"数据库加载成功"
            5. 左侧面板列出所有数据库表名
            6. "导出数据库"按钮变为可用状态

            双击任意表名:

            • 右侧网格自动填充该表的所有数据
            • 列标题显示字段名
            • 数据按行展示,支持滚动查看
            • 列宽自动调整适应内容
            • 标题栏显示表名和记录总数

            点击"导出数据库"按钮:

            1. 弹出保存对话框,默认文件名为ForguncyDB.sqlite3
            2. 选择保存位置并确认
            3. 如文件已存在,提示是否覆盖
            4. 导出成功后显示完整保存路径
            5. 状态栏更新显示导出信息

            以上就是使用wxPython开发FGCC数据库查看器的完整指南的详细内容,更多关于wxPython FGCC数据库查看器的资料请关注风君子博客其它相关文章!

            您可能感兴趣的文章:

            • 基于wxPython和DeepSeek API开发的智能批处理文件生成器
            • Python使用wxPython开发电脑信息二维码生成器
            • Python结合wxPython打造一个优雅的图片预览工具
            • 基于Python和wxPython打造一个智能日期文件夹管理工具
            • Python结合wxPython与PyMuPDF手搓一个PDF编辑器

            站内搜索