源码下载地址:https://download.csdn.net/download/zy0412326/12154342
链接:https://pan.baidu.com/s/1-s2WaQmV5bue8znirxWQ3Q 提取码:w0wo
学习Python一段时间,写了点东西。做了个GUI的小程序,和大家分享一下。这个小程序算不上框架,只是在工作过程中依据自己的需求编写的一个GUI小程序吧。使用了Python中WxPython技术,实现GUI可视化功能,目前在Windows和Mac OS上测试没有问题。Linux我相信也不会有问题,毕竟MacOS和Linux都是Unix内核。
先把使用的包给大家列举一下:Python 3.7、WxPython 4.0.4、pymysql、0.9.3、SQLAlchemy 1.2.17。其他的一些东西是Python自带的了这里就不再陈述。开发工具Pycharm专业版(估计社区版也可以)。
项目是按照传统ASP.NET的CodeBehand代码后置的方式设计的,即WxPython GUI代码和Python业务逻辑代码分离。也采用传统MVC模型,将各个层进行分离,实体类基于SQLAlchemy模型和用贫血模型进行编写。
下面给大家分享一下项目开发截图和程序运行的截图:
程序运行的截图:
接下来进入正题查阅每一层都是做什么的。
start层:负责GUI程序启动的类存放地点。仿照.NET WINFORM 的Program.cs类设计,在BootStrappy中进行GUI程序启动及配置的初始化。具体代码如下:
- import wx
- from main.base.BaseConfig import BaseConfig
- from main.controller.MainController import MainController
- if __name__ == '__main__':
- BaseConfig().__init_sys_config__() #初始化系统配置主要是sqlite数据库
- app = wx.App(False)
- controller = MainController()
- app.MainLoop()
- pass
View层:WxPython主要的代码。负责GUI的展示。MainView.py是项目的首页。首页包含日志菜单、日志显示区域、版权信息等。目前菜单还未进行权限的代码编写。下图是MainView.py的截图。
有个菜单核心方法initializeMenu(),新增的菜单都在这里体现,WxPython的菜单写法和JavaSwing的菜单写法非常类似。就连WxPython的部局和JavaSwing都非常类似。如果会JavaSwing学习WxPython基本无障碍。贴点代码给各位看看。
- def initializeMenu(self):
- self.menu_bar = wx.MenuBar() # 创建软件的菜单wx是三方控件默认在Frame类中存在MenuBar为页面的主菜单
- # region 系统配置10
- sysmenu = wx.Menu() # 创建子菜单软件菜单下的子菜单可以有多个和JavaSwing比较类似
- systemConfig = wx.MenuItem(sysmenu, wx.ID_SYSTEM_MENU, "系统配置") # 生成一个菜单项
- systemConfig_png_path = Tools.get_resourcepath("resource") + os.sep + 'png' + os.sep + "cog.png"
- systemConfig.SetBitmap(wx.Bitmap(systemConfig_png_path))
- sysmenu.Append(systemConfig)
- systemLog = wx.MenuItem(sysmenu, 1001, "系统日志")
- systemLog.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "clock_red.png"))
- sysmenu.Append(systemLog)
- systemLogin = wx.MenuItem(sysmenu, 1002, "系统登录") # 生成一个系统登录的菜单项
- systemLogin.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "user.png"))
- sysmenu.Append(systemLogin)
- baidu_api_config = wx.MenuItem(sysmenu, 1003, "邮箱配置") # 生成一个系统登录的菜单项
- baidu_api_config.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "email.png"))
- sysmenu.Append(baidu_api_config)
- baidu_api_config = wx.MenuItem(sysmenu, 1004, "百度API配置") # 生成一个系统登录的菜单项
- baidu_api_config.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "baidu.png"))
- sysmenu.Append(baidu_api_config)
- systemClose = wx.MenuItem(sysmenu, wx.ID_EXIT, "关闭系统", "&Quit\tCtrl+Q") # 生成一个关闭系统的菜单项
- systemClose.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "cancel.png"))
- sysmenu.Append(systemClose)
- # menuBar.Append(sysmenu, "系统设置")
- # endregion
- # region 帮助9
- helpMenu = wx.Menu()
- aboutMe = wx.MenuItem(helpMenu, wx.ID_ABOUT, "关于我们") # 生成一个关于我们的菜单项
- aboutMe.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "contrast.png"))
- helpMenu.Append(aboutMe)
- contracttUs = wx.MenuItem(helpMenu, 901, "联系我们") # 生成一个联系我们的菜单项
- contracttUs.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "email.png"))
- helpMenu.Append(contracttUs)
- opinionMenuItem = wx.MenuItem(helpMenu, 902, "意见反馈") # 生成一个意见反馈的菜单项
- opinionMenuItem.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "bug.png"))
- helpMenu.Append(opinionMenuItem)
- version_update = wx.MenuItem(helpMenu, 903, "版本检查")
- version_update.SetBitmap(wx.Bitmap(Tools.get_resource_png_path() + os.sep + "update.png"))
- helpMenu.Append(version_update)
- # menuBar.Append(helpMenu, "帮助")
- # endregion 帮助
- self.menu_bar.Append(sysmenu, "系统设置")
- self.menu_bar.Append(helpMenu, "帮助")
- self.SetMenuBar(self.menu_bar) # 创建菜单条
其实整个View中最难的是多线程更新UI。这个东东就是会了不难,难了不会,我也被困扰好久后来找到API就写出来了,网络上由有用的信息很多,但是不写版本号这个让人很头疼。无论是是C#、Java还是Python都有这个问题让我深度无语。Wxpython多线程更新UI的样例:https://blog.csdn.net/seakingx/article/details/91807771。以后会例举个专题讲一讲。
version层:主要是检查当前程序是否有最新版本,该层负责链接远端服务器。
resource层:整个项目所有的资源存放地点。
plugin层:整个项目工具类存放地点。
object层:整个项目实体类和枚举类存放地点。
controller层:整个项目controller类存放地点。与view层对应,CodeBehand代码。根据实际项目需要,如果需要写业务层则增加business层与之对接即可。不需要直接在controller中写业务代码。
base层:整个项目基础类存放地点。包含
- BaseConfig.py系统配置类,主要是路径配置,兼容mac和win。系统第一次安装的时候会把系统数据库(sqlite3)初始化到指定的目录。具体代码:
- import os
- import getpass
- from main.plugin.Tools import Tools
- class BaseConfig:
- # region 窗体变量
- INT_LOG_FILE_PATH = ""
- LOG_FILE_NAME = "toolkit-frame.log"
- LOG_FILE_PATH = "/Users/zhangyu/LandSea/"
- SOFT_VERSION = "AiToolkit"
- FILE_NAME = "toolkit.sqlite"
- # endregion
- # region 构造函数
- def __init__(self):
- resource_db = Tools.get_resourcepath("resource") + os.sep + "db" + os.sep + self.FILE_NAME
- if Tools.get_os_name() == "WIN":
- self.IS_LUX_OS = False
- self.IS_MAC_OS = False
- self.IS_WIN_OS = True
- self.CORPUS_ROOT = 'D:\\Landsea\\Train\\Corpus' # 语料库根路径
- self.ROOT_PATH = "C:\\Users\\" + getpass.getuser() + "\\AppData\\Local\\" + self.SOFT_VERSION + "\\"
- self.TEMP_PATH = "C:\\Users\\" + getpass.getuser() + "\\AppData\\Local\\" + self.SOFT_VERSION + "\\Temp\\"
- elif Tools.get_os_name() == "OS":
- self.IS_LUX_OS = False
- self.IS_MAC_OS = True
- self.IS_WIN_OS = False
- self.CORPUS_ROOT = '/Users/zhangyu/Corpus'
- self.ROOT_PATH = "/Users/" + getpass.getuser() + "/AppData/Local/" + self.SOFT_VERSION + "/"
- self.TEMP_PATH = "/Users/" + getpass.getuser() + "/AppData/Local/" + self.SOFT_VERSION + "/Temp/"
- elif Tools.get_os_name() == "LUX":
- self.IS_LUX_OS = True
- self.IS_MAC_OS = False
- self.IS_WIN_OS = False
- self.CORPUS_ROOT = '/Users/zhangyu/Corpus'
- self.ROOT_PATH = "/Users/" + getpass.getuser() + "/AppData/Local/" + self.SOFT_VERSION + "/"
- self.TEMP_PATH = "/Users/" + getpass.getuser() + "/AppData/Local/" + self.SOFT_VERSION + "/Temp/"
- else:
- self.IS_LUX_OS = False
- self.IS_MAC_OS = False
- self.IS_WIN_OS = False
- pass
- Tools.judge_diskpath_exits_create(self.ROOT_PATH)
- Tools.judge_diskpath_exits_create(self.TEMP_PATH)
- GLOBAL_CONFIG_PATH_NAME = self.ROOT_PATH + self.FILE_NAME
- if os.path.exists(GLOBAL_CONFIG_PATH_NAME):
- pass
- else:
- Tools.copy_file_to_disk(resource_db, GLOBAL_CONFIG_PATH_NAME)
- if Tools.judge_is_exits_network():
- self.EXITS_NET = True
- else:
- self.EXITS_NET = False
- # endregion
- # region 初始化系统配置文件 zhangyu-2019-5-25
- def __init_sys_config__(self):
- resource_db = Tools.get_resourcepath("resource") + os.sep + "db" + os.sep + self.FILE_NAME
- if Tools.get_os_name() == "WIN":
- self.IS_WIN_OS = True
- GLOBAL_CONFIG_PATH_NAME = self.ROOT_PATH + self.FILE_NAME
- Tools.judge_diskpath_exits_create(self.ROOT_PATH)
- Tools.judge_diskpath_exits_create(self.TEMP_PATH)
- if os.path.exists(GLOBAL_CONFIG_PATH_NAME):
- return
- else:
- Tools.copy_file_to_disk(resource_db, GLOBAL_CONFIG_PATH_NAME)
- return
- pass
- elif Tools.get_os_name() == "OS":
- self.IS_MAC_OS = True
- GLOBAL_CONFIG_PATH_NAME = self.ROOT_PATH + self.FILE_NAME
- Tools.judge_diskpath_exits_create(self.ROOT_PATH)
- Tools.judge_diskpath_exits_create(self.TEMP_PATH)
- if os.path.exists(GLOBAL_CONFIG_PATH_NAME):
- return
- else:
- Tools.copy_file_to_disk(resource_db, GLOBAL_CONFIG_PATH_NAME)
- return
- elif Tools.get_os_name() == "LUX":
- self.IS_LUX_OS = True
- Tools.judge_diskpath_exits_create(self.ROOT_PATH)
- Tools.judge_diskpath_exits_create(self.TEMP_PATH)
- pass
- pass
- # endregion
- BaseController.py Controller的基类。集成了系统配置类(BaseConfig.py),同时读取系统参数。
- from main.access.sys.SysConfigAccess import SysConfigAccess
- from main.base.BaseConfig import BaseConfig
- class BaseController(BaseConfig):
- def __init__(self):
- self.sys_list = SysConfigAccess().find_all()
- for entity in self.sys_list:
- if entity.parameter_key == "SOFT_NAME":
- self.soft_subject = entity.parameter_value
- if entity.parameter_key == "AUTO_TIME":
- self.auto_time = entity.parameter_value
- if entity.parameter_key == "CONFIG_PATH":
- self.config_path = (entity.parameter_value)
- if entity.parameter_key == "IS_TRANS":
- if entity.parameter_value == "1":
- self.is_auto_excute = True
- else:
- self.is_auto_excute = False
- if entity.parameter_key == "IS_SHOW_FRAME":
- if entity.parameter_value == "1":
- self.is_show_pop_win = True
- else:
- self.is_show_pop_win = False
- if entity.parameter_key == "IS_SPRIDER":
- if entity.parameter_value == "1":
- self.is_auto_sprider = True
- else:
- self.is_auto_sprider = False
- if entity.parameter_key == "TEMP_PATH":
- self.temp_path = (entity.parameter_value)
- pass
- BaseEntity.py
- BaseFrame.py
- MySqlAccess.py
- SqliteAccess.py
access层:整个项目数据访问类存放地点。主要是controller访问。
最后介绍requirements.txt文件。这里面是我使用的所有包。各位根据需要自己增加需要的包,