一、项目说明:

  本次通过实现一个小的功能模块对Python GUI进行实践学习。项目来源于软件制造工程的作业。记录在这里以复习下思路和总结编码过程。所有的源代码和文件放在这里:

    链接: https://pan.baidu.com/s/1qXGVRB2 密码: 4a4r

    内置四个文件,分别是ora.sql, dataBaseOpr.py, guiPy.py, test.py

二、效果预览:

    

                      主界面

    

                      新增界面(更新界面一致)

    功能很简单,就是做一张表的增删改查,借此简单的熟悉下python,前几天才看了看相关的语法。

三、环境说明:

  数据库采用oracle12c,使用命令行进行操作。Python版本为3.6.2,命令行+Pycharm社区版2017.1.4。Python库使用了

    cx_Oracle: 连接oracle数据库

         tkinter: 简单入门的GUI库

  cx_Oracle库的安装我直接使用IDE自带的包管理进行下载安装的,tkinter是Python3.2以后自带的标准库,后面会讲。

四、编码过程实现:

 1、数据库表实现(ora.sql):

    

    conn username/pass 根据本机的用户名和密码修改,后面的数据库连接统一都用我自己密码,不再赘述。

    

    

    为了简化Python代码和实践sql能力,写了两个简单的存储过程,分别是插入和更新,成功创建后只需调用存储过程和传递参数列表即可。代码详情在ora.sql中。

    代码折叠:

    

  1. conn c##bai/bai123
  2. --建表
  3. create or replace table groupinfo (
  4. no varchar(12) not null,
  5. name varchar(20),
  6. headername varchar(20),
  7. tel varchar(15),
  8. constraint pk_groupinfo primary key(no));
  9.  
  10. --创建过程,直接传入参数即可插入
  11. create or replace procedure insert_groupinfo
  12. (no groupinfo.no%type,
  13. name groupinfo.name%type,
  14. headername groupinfo.headername%type,
  15. tel groupinfo.tel%type
  16. )
  17. is
  18. begin
  19. insert into groupinfo values(no,name,headername,tel);
  20. commit;
  21. end;
  22.  
  23. --创建过程,直接传入参数即可完成更新,第一个字段为原纪录no。必须有。
  24. create or replace procedure update_groupinfo
  25. (oldno groupinfo.no%type,
  26. no groupinfo.no%type,
  27. name groupinfo.name%type,
  28. headername groupinfo.headername%type,
  29. tel groupinfo.tel%type
  30. )
  31. is
  32. n_no groupinfo.no%type;
  33. n_name groupinfo.name%type;
  34. n_headername groupinfo.headername%type;
  35. n_tel groupinfo.tel%type;
  36. grow groupinfo%rowtype;
  37. ex_oldnoisnull exception;
  38. begin
  39. select * into grow from groupinfo g where g.no=oldno;
  40. if oldno is null or grow.no is null then
  41. raise ex_oldnoisnull;
  42. end if;
  43. if no is null then
  44. n_no:= oldno;
  45. else
  46. n_no:= no;
  47. end if;
  48. if name is null then
  49. n_name:= grow.name;
  50. else
  51. n_name:= name;
  52. end if;
  53. if headername is null then
  54. n_headername:= grow.headername;
  55. else
  56. n_headername:= headername;
  57. end if;
  58. if tel is null then
  59. n_tel:= grow.tel;
  60. else
  61. n_tel:= tel;
  62. end if;
  63. --dbms_output.put_line(n_no||n_name||n_headername||n_tel);
  64. update groupinfo g set g.no = n_no, g.name = n_name, g.headername = n_headername, g.tel = n_tel where g.no = oldno;
  65. commit;
  66. exception
  67. when ex_oldnoisnull then
  68. dbms_output.out_line('选择的行不存在')
  69. end;

ora.sql

 2、数据库操作类(dataBaseOpr.py):

    先贴源码,折叠起来:

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. """
  4. :author: xiaoxiaobai
  5.  
  6. :contact: 865816863@qq.com
  7.  
  8. :file: dataBaseOpr.py
  9.  
  10. :time: 2017/10/3 12:04
  11.  
  12. :@Software: PyCharm Community Edition
  13.  
  14. :desc: 连接oracle数据库,并封装了增删改查全部操作。
  15.  
  16. """
  17. import cx_Oracle
  18.  
  19. class OracleOpr:
  20.  
  21. def __init__(self, username='c##bai', passname='bai123', ip='localhost', datebasename='orcl', ipport=''):
  22. """
  23. :param username: 连接数据库的用户名
  24. :param passname: 连接数据库的密码
  25. :param ip: 数据库ip
  26. :param datebasename:数据库名
  27. :param ipport: 数据库端口
  28. :desc: 初始化函数用于完成数据库连接,可以通过self.connStatus判断是否连接成功,成功则参数为0,不成功则返回错误详情
  29. """
  30. try:
  31. self.connStatus = '未连接' # 连接状态
  32. self.queryStatus = 0 # 查询状态
  33. self.updateStatus = 0 # 更新状态
  34. self.deleteStatus = 0 # 删除状态
  35. self.insertStatus = 0 # 插入状态
  36. self.__conn = ''
  37. self.__conStr = username+'/'+passname+'@'+ip+':'+ipport+'/'+datebasename
  38. self.__conn = cx_Oracle.connect(self.__conStr)
  39. self.connStatus = 0
  40. except cx_Oracle.Error as e:
  41. self.connStatus = e
  42.  
  43. def closeconnection(self):
  44. try:
  45. if self.__conn:
  46. self.__conn.close()
  47. self.connStatus = '连接已断开'
  48. except cx_Oracle.Error as e:
  49. self.connStatus = e
  50.  
  51. def query(self, table='groupinfo', queryby=''):
  52. """
  53. :param table: 查询表名
  54. :param queryby: 查询条件,支持完整where, order by, group by 字句
  55. :return:返回数据集,列名
  56. """
  57. self.queryStatus = 0
  58. result = ''
  59. cursor = ''
  60. title = ''
  61. try:
  62. sql = 'select * from '+table+' '+queryby
  63. print(sql)
  64. cursor = self.__conn.cursor()
  65. cursor.execute(sql)
  66. result = cursor.fetchall()
  67. title = [i[0] for i in cursor.description]
  68. cursor.close()
  69. cursor = ''
  70. except cx_Oracle.Error as e:
  71. self.queryStatus = e
  72. finally:
  73. if cursor:
  74. cursor.close()
  75. return result, title
  76.  
  77. def insert(self, proc='insert_groupinfo', insertlist=[]):
  78. """
  79. :param proc: 过程名
  80. :param insertlist: 参数集合,主键不能为空,参数必须与列对应,数量一致
  81. :desc: 此方法通过调用过程完成插入,需要在sql上完成存储过程,可以通过insertstatus的值判断是否成功
  82. """
  83. self.insertStatus = 0
  84. cursor = ''
  85. try:
  86. cursor = self.__conn.cursor()
  87. cursor.callproc(proc, insertlist)
  88. cursor.close()
  89. cursor = ''
  90. except cx_Oracle.Error as e:
  91. self.insertStatus = e
  92. finally:
  93. if cursor:
  94. cursor.close()
  95.  
  96. def update(self, proc='update_groupinfo', updatelist=[]):
  97. """
  98. :param proc: 存储过程名
  99. :param updatelist: 更新的集合,第一个为查询主键,后面的参数为对应的列,可以更新主键。
  100. :desc: 此方法通过调用存储过程完成更新操作,可以通过updatestatus的值判断是否成功
  101. """
  102. self.updateStatus = 0
  103. cursor = ''
  104. try:
  105. cursor = self.__conn.cursor()
  106. cursor.callproc(proc, updatelist)
  107. cursor.close()
  108. cursor = ''
  109. except cx_Oracle.Error as e:
  110. self.updateStatus = e
  111. finally:
  112. if cursor:
  113. cursor.close()
  114.  
  115. def delete(self, deleteby: '删除条件,where关键词后面的内容,即列名=列值(可多个组合)', table='groupinfo'):
  116. """
  117. :param deleteby: 删除的条件,除where关键字以外的内容
  118. :param table: 要删除的表名
  119. :desc:可以通过deletestatus判断是否成功删除
  120. """
  121. self.deleteStatus = 0
  122. cursor = ''
  123. try:
  124. sql = 'delete ' + table + ' where ' + deleteby
  125. cursor = self.__conn.cursor()
  126. cursor.execute(sql)
  127. cursor.close()
  128. cursor = ''
  129. except cx_Oracle.Error as e:
  130. self.deleteStatus = e
  131. finally:
  132. if cursor:
  133. cursor.close()

dataBaseOpr.py

    源码注释基本很清晰了,对关键点进行说明:数据库连接的数据全部用默认参数的形式给出了,可根据实际情况进行移植。关于调用存储过程,只需要使用connect(**).cursor.callproc(存储过程名, 参数列表)即可,方便高效。

 3、GUI界面搭建(tkinter):

    因为界面和逻辑我都写在guiPy.py中的,没有使用特别的设计模式。所以这一部分主要讲tkinter的用法,下一部分说明具体的实现。

    关于安装:Python3.2后自带本库,若引用没有,很可能是安装的时候没有选。解决方案嘛找到安装文件修改安装即可,如下图:

    

    

    下一步打上勾即可,完成安装就能引用tkinter了。

  使用教程简单介绍:

  我这次用的时候就是在网上随便搜了一下教程,发现内容都很浅显,而且不系统,当然我也没法系统的讲清楚,但官方文档可以啊,提醒自己,以后一定先看官方文档!

  http://effbot.org/tkinterbook/tkinter-index.htm

 4、逻辑实现(guiPy.py):

    先上代码,基本注释都有:

  1. #!/usr/bin/env python
  2. # encoding: utf-8
  3. """
  4. :author: xiaoxiaobai
  5.  
  6. :contact: 865816863@qq.com
  7.  
  8. :file: guiPy.py
  9.  
  10. :time: 2017/10/3 19:42
  11.  
  12. :@Software: PyCharm Community Edition
  13.  
  14. :desc: 该文件完成了主要窗体设计,和数据获取,呈现等操作。调用时,运行主类MainWindow即可
  15.  
  16. """
  17. import tkinter as tk
  18. from tkinter import ttk
  19. from dataBaseOpr import *
  20. import tkinter.messagebox
  21.  
  22. class MainWindow(tk.Tk):
  23. def __init__(self):
  24. super().__init__()
  25.  
  26. # 变量定义
  27. self.opr = OracleOpr()
  28. self.list = self.init_data()
  29. self.item_selection = ''
  30. self.data = []
  31.  
  32. # 定义区域,把全局分为上中下三部分
  33. self.frame_top = tk.Frame(width=600, height=90)
  34. self.frame_center = tk.Frame(width=600, height=180)
  35. self.frame_bottom = tk.Frame(width=600, height=90)
  36.  
  37. # 定义上部分区域
  38. self.lb_tip = tk.Label(self.frame_top, text="评议小组名称")
  39. self.string = tk.StringVar()
  40. self.string.set('')
  41. self.ent_find_name = tk.Entry(self.frame_top, textvariable=self.string)
  42. self.btn_query = tk.Button(self.frame_top, text="查询", command=self.query)
  43. self.lb_tip.grid(row=0, column=0, padx=15, pady=30)
  44. self.ent_find_name.grid(row=0, column=1, padx=45, pady=30)
  45. self.btn_query.grid(row=0, column=2, padx=45, pady=30)
  46.  
  47. # 定义下部分区域
  48. self.btn_delete = tk.Button(self.frame_bottom, text="删除", command=self.delete)
  49. self.btn_update = tk.Button(self.frame_bottom, text="修改", command=self.update)
  50. self.btn_add = tk.Button(self.frame_bottom, text="添加", command=self.add)
  51. self.btn_delete.grid(row=0, column=0, padx=20, pady=30)
  52. self.btn_update.grid(row=0, column=1, padx=120, pady=30)
  53. self.btn_add.grid(row=0, column=2, padx=30, pady=30)
  54.  
  55. # 定义中心列表区域
  56. self.tree = ttk.Treeview(self.frame_center, show="headings", height=8, columns=("a", "b", "c", "d"))
  57. self.vbar = ttk.Scrollbar(self.frame_center, orient=tk.VERTICAL, command=self.tree.yview)
  58. # 定义树形结构与滚动条
  59. self.tree.configure(yscrollcommand=self.vbar.set)
  60. # 表格的标题
  61. self.tree.column("a", width=80, anchor="center")
  62. self.tree.column("b", width=120, anchor="center")
  63. self.tree.column("c", width=120, anchor="center")
  64. self.tree.column("d", width=120, anchor="center")
  65. self.tree.heading("a", text="小组编号")
  66. self.tree.heading("b", text="小组名称")
  67. self.tree.heading("c", text="负责人")
  68. self.tree.heading("d", text="联系方式")
  69. # 调用方法获取表格内容插入及树基本属性设置
  70. self.tree["selectmode"] = "browse"
  71. self.get_tree()
  72. self.tree.grid(row=0, column=0, sticky=tk.NSEW, ipadx=10)
  73. self.vbar.grid(row=0, column=1, sticky=tk.NS)
  74.  
  75. # 定义整体区域
  76. self.frame_top.grid(row=0, column=0, padx=60)
  77. self.frame_center.grid(row=1, column=0, padx=60, ipady=1)
  78. self.frame_bottom.grid(row=2, column=0, padx=60)
  79. self.frame_top.grid_propagate(0)
  80. self.frame_center.grid_propagate(0)
  81. self.frame_bottom.grid_propagate(0)
  82.  
  83. # 窗体设置
  84. self.center_window(600, 360)
  85. self.title('评议小组管理')
  86. self.resizable(False, False)
  87. self.mainloop()
  88.  
  89. # 窗体居中
  90. def center_window(self, width, height):
  91. screenwidth = self.winfo_screenwidth()
  92. screenheight = self.winfo_screenheight()
  93. # 宽高及宽高的初始点坐标
  94. size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
  95. self.geometry(size)
  96.  
  97. # 数据初始化获取
  98. def init_data(self):
  99. result, _ = self.opr.query()
  100. if self.opr.queryStatus:
  101. return 0
  102. else:
  103. return result
  104.  
  105. # 表格内容插入
  106. def get_tree(self):
  107. if self.list == 0:
  108. tkinter.messagebox.showinfo("错误提示", "数据获取失败")
  109. else:
  110. # 删除原节点
  111. for _ in map(self.tree.delete, self.tree.get_children("")):
  112. pass
  113. # 更新插入新节点
  114. for i in range(len(self.list)):
  115. group = self.list[i]
  116. self.tree.insert("", "end", values=(group[0],
  117. group[1],
  118. group[2],
  119. group[3]), text=group[0])
  120. # TODO 此处需解决因主程序自动刷新引起的列表项选中后重置的情况,我采用的折中方法是:把选中时的数据保存下来,作为记录
  121.  
  122. # 绑定列表项单击事件
  123. self.tree.bind("<ButtonRelease-1>", self.tree_item_click)
  124. self.tree.after(500, self.get_tree)
  125.  
  126. # 单击查询按钮触发的事件方法
  127. def query(self):
  128. query_info = self.ent_find_name.get()
  129. self.string.set('')
  130. # print(query_info)
  131. if query_info is None or query_info == '':
  132. tkinter.messagebox.showinfo("警告", "查询条件不能为空!")
  133. self.get_tree()
  134. else:
  135. result, _ = self.opr.query(queryby="where name like '%" + query_info + "%'")
  136. self.get_tree()
  137. if self.opr.queryStatus:
  138. tkinter.messagebox.showinfo("警告", "查询出错,请检查数据库服务是否正常")
  139. elif not result:
  140. tkinter.messagebox.showinfo("查询结果", "该查询条件没有匹配项!")
  141. else:
  142. self.list = result
  143. # TODO 此处需要解决弹框后代码列表刷新无法执行的问题
  144.  
  145. # 单击删除按钮触发的事件方法
  146. def delete(self):
  147. if self.item_selection is None or self.item_selection == '':
  148. tkinter.messagebox.showinfo("删除警告", "未选中待删除值")
  149. else:
  150. # TODO: 删除提示
  151. self.opr.delete(deleteby="no = '"+self.item_selection+"'")
  152. if self.opr.deleteStatus:
  153. tkinter.messagebox.showinfo("删除警告", "删除异常,可能是数据库服务意外关闭了。。。")
  154. else:
  155. self.list = self.init_data()
  156. self.get_tree()
  157.  
  158. # 为解决窗体自动刷新的问题,记录下单击项的内容
  159. def tree_item_click(self, event):
  160. try:
  161. selection = self.tree.selection()[0]
  162. self.data = self.tree.item(selection, "values")
  163. self.item_selection = self.data[0]
  164. except IndexError:
  165. tkinter.messagebox.showinfo("单击警告", "单击结果范围异常,请重新选择!")
  166.  
  167. # 单击更新按钮触发的事件方法
  168. def update(self):
  169. if self.item_selection is None or self.item_selection == '':
  170. tkinter.messagebox.showinfo("更新警告", "未选中待更新项")
  171. else:
  172. data = [self.item_selection]
  173. self.data = self.set_info(2)
  174. if self.data is None or not self.data:
  175. return
  176. # 更改参数
  177. data = data + self.data
  178. self.opr.update(updatelist=data)
  179. if self.opr.insertStatus:
  180. tkinter.messagebox.showinfo("更新小组信息警告", "数据异常库连接异常,可能是服务关闭啦~")
  181. # 更新界面,刷新数据
  182. self.list = self.init_data()
  183. self.get_tree()
  184.  
  185. # 单击新增按钮触发的事件方法
  186. def add(self):
  187. # 接收弹窗的数据
  188. self.data = self.set_info(1)
  189. if self.data is None or not self.data:
  190. return
  191. # 更改参数
  192. self.opr.insert(insertlist=self.data)
  193. if self.opr.insertStatus:
  194. tkinter.messagebox.showinfo("新增小组信息警告", "数据异常库连接异常,可能是服务关闭啦~")
  195. # 更新界面,刷新数据
  196. self.list = self.init_data()
  197. self.get_tree()
  198.  
  199. # 此方法调用弹窗传递参数,并返回弹窗的结果
  200. def set_info(self, dia_type):
  201. """
  202. :param dia_type:表示打开的是新增窗口还是更新窗口,新增则参数为1,其余参数为更新
  203. :return: 返回用户填写的数据内容,出现异常则为None
  204. """
  205. dialog = MyDialog(data=self.data, dia_type=dia_type)
  206. # self.withdraw()
  207. self.wait_window(dialog) # 这一句很重要!!!
  208. return dialog.group_info
  209.  
  210. # 新增窗口或者更新窗口
  211. class MyDialog(tk.Toplevel):
  212. def __init__(self, data, dia_type):
  213. super().__init__()
  214.  
  215. # 窗口初始化设置,设置大小,置顶等
  216. self.center_window(600, 360)
  217. self.wm_attributes("-topmost", 1)
  218. self.resizable(False, False)
  219. self.protocol("WM_DELETE_WINDOW", self.donothing) # 此语句用于捕获关闭窗口事件,用一个空方法禁止其窗口关闭。
  220.  
  221. # 根据参数类别进行初始化
  222. if dia_type == 1:
  223. self.title('新增小组信息')
  224. else:
  225. self.title('更新小组信息')
  226.  
  227. # 数据变量定义
  228. self.no = tk.StringVar()
  229. self.name = tk.StringVar()
  230. self.pname = tk.StringVar()
  231. self.pnum = tk.StringVar()
  232. if not data or dia_type == 1:
  233. self.no.set('')
  234. self.name.set('')
  235. self.pname.set('')
  236. self.pnum.set('')
  237. else:
  238. self.no.set(data[0])
  239. self.name.set(data[1])
  240. self.pname.set(data[2])
  241. self.pnum.set(data[3])
  242.  
  243. # 错误提示定义
  244. self.text_error_no = tk.StringVar()
  245. self.text_error_name = tk.StringVar()
  246. self.text_error_pname = tk.StringVar()
  247. self.text_error_pnum = tk.StringVar()
  248. self.error_null = '该项内容不能为空!'
  249. self.error_exsit = '该小组编号已存在!'
  250.  
  251. self.group_info = []
  252. # 弹窗界面布局
  253. self.setup_ui()
  254.  
  255. # 窗体布局设置
  256. def setup_ui(self):
  257. # 第一行(两列)
  258. row1 = tk.Frame(self)
  259. row1.grid(row=0, column=0, padx=160, pady=20)
  260. tk.Label(row1, text='小组编号:', width=8).pack(side=tk.LEFT)
  261. tk.Entry(row1, textvariable=self.no, width=20).pack(side=tk.LEFT)
  262. tk.Label(row1, textvariable=self.text_error_no, width=20, fg='red').pack(side=tk.LEFT)
  263. # 第二行
  264. row2 = tk.Frame(self)
  265. row2.grid(row=1, column=0, padx=160, pady=20)
  266. tk.Label(row2, text='小组名称:', width=8).pack(side=tk.LEFT)
  267. tk.Entry(row2, textvariable=self.name, width=20).pack(side=tk.LEFT)
  268. tk.Label(row2, textvariable=self.text_error_name, width=20, fg='red').pack(side=tk.LEFT)
  269. # 第三行
  270. row3 = tk.Frame(self)
  271. row3.grid(row=2, column=0, padx=160, pady=20)
  272. tk.Label(row3, text='负责人姓名:', width=10).pack(side=tk.LEFT)
  273. tk.Entry(row3, textvariable=self.pname, width=18).pack(side=tk.LEFT)
  274. tk.Label(row3, textvariable=self.text_error_pname, width=20, fg='red').pack(side=tk.LEFT)
  275. # 第四行
  276. row4 = tk.Frame(self)
  277. row4.grid(row=3, column=0, padx=160, pady=20)
  278. tk.Label(row4, text='手机号码:', width=8).pack(side=tk.LEFT)
  279. tk.Entry(row4, textvariable=self.pnum, width=20).pack(side=tk.LEFT)
  280. tk.Label(row4, textvariable=self.text_error_pnum, width=20, fg='red').pack(side=tk.LEFT)
  281. # 第五行
  282. row5 = tk.Frame(self)
  283. row5.grid(row=4, column=0, padx=160, pady=20)
  284. tk.Button(row5, text="取消", command=self.cancel).grid(row=0, column=0, padx=60)
  285. tk.Button(row5, text="确定", command=self.ok).grid(row=0, column=1, padx=60)
  286.  
  287. def center_window(self, width, height):
  288. screenwidth = self.winfo_screenwidth()
  289. screenheight = self.winfo_screenheight()
  290. size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
  291. self.geometry(size)
  292.  
  293. # 点击确认按钮绑定事件方法
  294. def ok(self):
  295.  
  296. self.group_info = [self.no.get(), self.name.get(), self.pname.get(), self.pnum.get()] # 设置数据
  297. if self.check_info() == 1: # 进行数据校验,失败则不关闭窗口
  298. return
  299. self.destroy() # 销毁窗口
  300.  
  301. # 点击取消按钮绑定事件方法
  302. def cancel(self):
  303. self.group_info = None # 空!
  304. self.destroy()
  305.  
  306. # 数据校验和用户友好性提示,校验失败返回1,成功返回0
  307. def check_info(self):
  308. is_null = 0
  309. str_tmp = self.group_info
  310. if str_tmp[0] == '':
  311. self.text_error_no.set(self.error_null)
  312. is_null = 1
  313. if str_tmp[1] == '':
  314. self.text_error_name.set(self.error_null)
  315. is_null = 1
  316. if str_tmp[2] == '':
  317. self.text_error_pname.set(self.error_null)
  318. is_null = 1
  319. if str_tmp[3] == '':
  320. self.text_error_pnum.set(self.error_null)
  321. is_null = 1
  322.  
  323. if is_null == 1:
  324. return 1
  325. res, _ = OracleOpr().query(queryby="where no = '"+str_tmp[0]+"'")
  326. print(res)
  327. if res:
  328. self.text_error_no.set(self.error_exsit)
  329. return 1
  330. return 0
  331.  
  332. # 空函数
  333. def donothing(self):
  334. pass

guiPy.py

  可以看的出,窗体类继承自tkinter.TK()可以直接通过self.x对主窗体添加控件和修改属性。然后在初始化函数中需要声明需要的成员变量,完成整体布局以及控件的事件绑定,以及数据初始化,最后self.mainloop()使窗体完成自动刷新。我们所有的逻辑处理都是在事件绑定方法中完成的,这样感觉就像是针对用户的每一个操作做出对应的逻辑处理和反应,同时需要考虑可能出现的异常以及所有的可能性,达到用户友好的设计要求。

  运行此实例,可以使用test,py中的测试方法,也可以把guiPy.py和dataBaseOpr.py两个类放在同一个文件夹,在本机安装好上述两个库和完成数据库创建的情况下,直接在py解释器下导入guiPy.py文件下所有的包,MainWindow()即可。

python GUI实战项目——tkinter库的简单实例的更多相关文章

  1. 如何美观地打印 Python 对象?这个标准库可以简单实现

    前不久,我写了一篇文章回顾 Python 中 print 的发展历史 ,提到了两条发展线索: 明线:早期的 print 语句带有 C 和 Shell 的影子,是个应用程序级的 statement,在最 ...

  2. [python]近日 用3种库 实现简单的窗口 的回顾~

    最近任务:利用python 实现以下4个窗口弹窗. 信息提示框 文本输入框(需在窗口消失后,返回 用户输入的值) 文件选择(需在窗口消失后, 返回 用户选择的文件名的全路径) 文件夹选择(需在窗口消失 ...

  3. python fastApi实战项目 - 爱投票管理系统(一)

    一.闲来无事,在工作之余自己研究了一下python的异步框架 - fastapi,并写包括 1.部门管理 2.角色管理 3.用户管理 4.菜单管理 5.登录日志 6.操作日志 六个基础功能模块,演示链 ...

  4. 32个Python爬虫实战项目,满足你的项目慌

    爬虫项目名称及简介 一些项目名称涉及企业名词,小编用拼写代替 1.[WechatSogou]- weixin公众号爬虫.基于weixin公众号爬虫接口,可以扩展成其他搜索引擎的爬虫,返回结果是列表,每 ...

  5. Python GUI编程(TKinter)(简易计算器)

    搞课设搞得心累,现在看到人脸这两个字就烦躁,无聊搞搞tkinter,实现一个计算器的功能,能够简单的加减乘除. 简单的页面如下: 简单的代码如下: # encoding:utf-8 import tk ...

  6. Python -- Gui编程 -- Tkinter的使用 -- 基本控件

    1.按钮 tkBtton.py import tkinter root = tkinter.Tk() btn1 = tkinter.Button(root, anchor=tkinter.E,\ te ...

  7. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介

    Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...

  8. 再一波Python实战项目列表

    前言: 近几年Python可谓是大热啊,很多人都纷纷投入Python的学习中,以前我们实验楼总结过多篇Python实战项目列表,不但有用还有趣,最主要的是咱们实验楼不但有详细的开发教程,更有在线开发环 ...

  9. Python GUI - tkinter

    目录: Tkinter 组件 标准属性 几何管理 代码实例: 1. Label & Button 2. Entry & Text 3.Listbox列表 4.Radiobutton单选 ...

随机推荐

  1. maven 随笔

    <build> <plugins> <!--打包源代码--> <plugin> <artifactId>maven-source-plugi ...

  2. wireshark 随笔

    在进行通信开发的过程中,我们往往会把本机既作为客户端又作为服务器端来调试代码,使得本机自己和自己通信.但是wireshark此时是无法抓取到数据包的,需要通过简单的设置才可以. 具体方法如下: ①:以 ...

  3. Java基础精选,你答对了几道?

    没有技术深度是大多程序员的一种常态. 但是当你成为一个资深的工程师的时候,很多公司并不希望你还是那样平庸,没有深度.虽然你会纳闷,我就算有深度你们也不一定用得上呀?然而到了这个级别的人需求量并不像初中 ...

  4. 后台方庄List razor 循环

    后台: //1.查询所有年卡类型                StringBuilder sqlStr = new StringBuilder();                sqlStr.Ap ...

  5. JSONP的实现流程

    在进行AJAX的时候会经常产生这样一个报错: 看红字,这是浏览器的同源策略,使跨域进行的AJAX无效.注意,不是不发送AJAX请求(其实就是HTTP请求),而是请求了,也返回了,但浏览器‘咔擦’一声, ...

  6. 如何解决xshell中无法输入中文的问题

    自从安上了xshell以后,用着那叫一个顺手,美中不足的就是一直无法输入中文.不过,既然学习IT,就要习惯英文嘛~直到--我遇到了脚本,写好一个脚本,必要的注释是少不了的,但是作为一个英文渣渣,我真的 ...

  7. 201521123091 《Java程序设计》第12周学习总结

    Java 第十一周总结 第十一周的作业. 目录 1.本章学习总结 2.Java Q&A 3.码云上代码提交记录及PTA实验总结 4.课后阅读 1.本章学习总结 1.1 以你喜欢的方式(思维导图 ...

  8. 姑娘你大胆地往前走——答大二学生XCL之八问

    姑娘你大胆地往前走--答大二学生XCL之八问 以下问题的答案写给我家正在读大二的XCL. 写于 2017-9-13 晚 请问您是为什么选择了IT行业的? 与其说是我选择了行业,不如说是行业选择了我. ...

  9. 团队作业8——第二次项目冲刺(Beta阶段)(冲刺计划)

    Beta阶段冲刺计划 Alpha冲刺暂时告一段落,项目现在也有个了大体框架,当然还是有很多漏洞,在接下来的Beta冲刺中尽量完善,希望最后能有一个好的结果. 新成员介绍 何跃斌:掌握java.c的基本 ...

  10. 201521123042 《java程序设计》 第八周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. ①泛型定义:泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展, ...