python tkinter库_python GUI实战项目——tkinter库的简单实例

一、项目说明:

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

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

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

二、效果预览:

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA4MzAzMjMxOC01MDEwNTAyMjYucG5n.jpg

主界面

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA4MzIxMTAyMS0xMDIyNjg4NzE1LnBuZw==.jpg

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

功能很简单,就是做一张表的增删改查,借此简单的熟悉下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):

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA4NDY0NjcyNC01NjUxNDE4MzgucG5n.jpg

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

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA4NDkzODgxOC0zMjM2NDQ3OTYucG5n.jpg

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA4NDkwOTAzNi0xMjA0Mjc5OTE0LnBuZw==.jpg

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

代码折叠:

conn c##bai/bai123

--建表

create or replace table groupinfo (

no varchar(12) not null,

name varchar(20),

headername varchar(20),

tel varchar(15),

constraint pk_groupinfo primary key(no));

--创建过程,直接传入参数即可插入

create or replace procedure insert_groupinfo

(no groupinfo.no%type,

name groupinfo.name%type,

headername groupinfo.headername%type,

tel groupinfo.tel%type

)

is

begin

insert into groupinfo values(no,name,headername,tel);

commit;

end;

--创建过程,直接传入参数即可完成更新,第一个字段为原纪录no。必须有。

create or replace procedure update_groupinfo

(oldno groupinfo.no%type,

no groupinfo.no%type,

name groupinfo.name%type,

headername groupinfo.headername%type,

tel groupinfo.tel%type

)

is

n_no groupinfo.no%type;

n_name groupinfo.name%type;

n_headername groupinfo.headername%type;

n_tel groupinfo.tel%type;

grow groupinfo%rowtype;

ex_oldnoisnull exception;

begin

select * into grow from groupinfo g where g.no=oldno;

if oldno is null or grow.no is null then

raise ex_oldnoisnull;

end if;

if no is null then

n_no:= oldno;

else

n_no:= no;

end if;

if name is null then

n_name:= grow.name;

else

n_name:= name;

end if;

if headername is null then

n_headername:= grow.headername;

else

n_headername:= headername;

end if;

if tel is null then

n_tel:= grow.tel;

else

n_tel:= tel;

end if;

--dbms_output.put_line(n_no||n_name||n_headername||n_tel);

update groupinfo g set g.no = n_no, g.name = n_name, g.headername = n_headername, g.tel = n_tel where g.no = oldno;

commit;

exception

when ex_oldnoisnull then

dbms_output.out_line('选择的行不存在')

end;

ora.sql

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

先贴源码,折叠起来:

#!/usr/bin/env python

# encoding: utf-8

"""

:author: xiaoxiaobai

:contact: 865816863@qq.com

:file: dataBaseOpr.py

:time: 2017/10/3 12:04

:@Software: PyCharm Community Edition

:desc: 连接oracle数据库,并封装了增删改查全部操作。

"""

import cx_Oracle

class OracleOpr:

def __init__(self, username='c##bai', passname='bai123', ip='localhost', datebasename='orcl', ipport=''):

"""

:param username: 连接数据库的用户名

:param passname: 连接数据库的密码

:param ip: 数据库ip

:param datebasename:数据库名

:param ipport: 数据库端口

:desc: 初始化函数用于完成数据库连接,可以通过self.connStatus判断是否连接成功,成功则参数为0,不成功则返回错误详情

"""

try:

self.connStatus = '未连接' # 连接状态

self.queryStatus = 0 # 查询状态

self.updateStatus = 0 # 更新状态

self.deleteStatus = 0 # 删除状态

self.insertStatus = 0 # 插入状态

self.__conn = ''

self.__conStr = username+'/'+passname+'@'+ip+':'+ipport+'/'+datebasename

self.__conn = cx_Oracle.connect(self.__conStr)

self.connStatus = 0

except cx_Oracle.Error as e:

self.connStatus = e

def closeconnection(self):

try:

if self.__conn:

self.__conn.close()

self.connStatus = '连接已断开'

except cx_Oracle.Error as e:

self.connStatus = e

def query(self, table='groupinfo', queryby=''):

"""

:param table: 查询表名

:param queryby: 查询条件,支持完整where, order by, group by 字句

:return:返回数据集,列名

"""

self.queryStatus = 0

result = ''

cursor = ''

title = ''

try:

sql = 'select * from '+table+' '+queryby

print(sql)

cursor = self.__conn.cursor()

cursor.execute(sql)

result = cursor.fetchall()

title = [i[0] for i in cursor.description]

cursor.close()

cursor = ''

except cx_Oracle.Error as e:

self.queryStatus = e

finally:

if cursor:

cursor.close()

return result, title

def insert(self, proc='insert_groupinfo', insertlist=[]):

"""

:param proc: 过程名

:param insertlist: 参数集合,主键不能为空,参数必须与列对应,数量一致

:desc: 此方法通过调用过程完成插入,需要在sql上完成存储过程,可以通过insertstatus的值判断是否成功

"""

self.insertStatus = 0

cursor = ''

try:

cursor = self.__conn.cursor()

cursor.callproc(proc, insertlist)

cursor.close()

cursor = ''

except cx_Oracle.Error as e:

self.insertStatus = e

finally:

if cursor:

cursor.close()

def update(self, proc='update_groupinfo', updatelist=[]):

"""

:param proc: 存储过程名

:param updatelist: 更新的集合,第一个为查询主键,后面的参数为对应的列,可以更新主键。

:desc: 此方法通过调用存储过程完成更新操作,可以通过updatestatus的值判断是否成功

"""

self.updateStatus = 0

cursor = ''

try:

cursor = self.__conn.cursor()

cursor.callproc(proc, updatelist)

cursor.close()

cursor = ''

except cx_Oracle.Error as e:

self.updateStatus = e

finally:

if cursor:

cursor.close()

def delete(self, deleteby: '删除条件,where关键词后面的内容,即列名=列值(可多个组合)', table='groupinfo'):

"""

:param deleteby: 删除的条件,除where关键字以外的内容

:param table: 要删除的表名

:desc:可以通过deletestatus判断是否成功删除

"""

self.deleteStatus = 0

cursor = ''

try:

sql = 'delete ' + table + ' where ' + deleteby

cursor = self.__conn.cursor()

cursor.execute(sql)

cursor.close()

cursor = ''

except cx_Oracle.Error as e:

self.deleteStatus = e

finally:

if cursor:

cursor.close()

dataBaseOpr.py

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

3、GUI界面搭建(tkinter):

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

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

L3Byb3h5L2h0dHBzL2NvbW1vbi5jbmJsb2dzLmNvbS9pbWFnZXMvbG9hZGluZy5naWY=.jpg即可,如下图:

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA5MTczNTg5Ni0yMDc3NzY0MDM4LnBuZw==.jpg

L3Byb3h5L2h0dHBzL2ltYWdlczIwMTcuY25ibG9ncy5jb20vYmxvZy84MjgyMTQvMjAxNzEwLzgyODIxNC0yMDE3MTAwNzA5MTgwMjAwNS00MTI4MTcyNTgucG5n.jpg

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

使用教程简单介绍:

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

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

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

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

#!/usr/bin/env python

# encoding: utf-8

"""

:author: xiaoxiaobai

:contact: 865816863@qq.com

:file: guiPy.py

:time: 2017/10/3 19:42

:@Software: PyCharm Community Edition

:desc: 该文件完成了主要窗体设计,和数据获取,呈现等操作。调用时,运行主类MainWindow即可

"""

import tkinter as tk

from tkinter import ttk

from dataBaseOpr import *

import tkinter.messagebox

class MainWindow(tk.Tk):

def __init__(self):

super().__init__()

# 变量定义

self.opr = OracleOpr()

self.list = self.init_data()

self.item_selection = ''

self.data = []

# 定义区域,把全局分为上中下三部分

self.frame_top = tk.Frame(width=600, height=90)

self.frame_center = tk.Frame(width=600, height=180)

self.frame_bottom = tk.Frame(width=600, height=90)

# 定义上部分区域

self.lb_tip = tk.Label(self.frame_top, text="评议小组名称")

self.string = tk.StringVar()

self.string.set('')

self.ent_find_name = tk.Entry(self.frame_top, textvariable=self.string)

self.btn_query = tk.Button(self.frame_top, text="查询", command=self.query)

self.lb_tip.grid(row=0, column=0, padx=15, pady=30)

self.ent_find_name.grid(row=0, column=1, padx=45, pady=30)

self.btn_query.grid(row=0, column=2, padx=45, pady=30)

# 定义下部分区域

self.btn_delete = tk.Button(self.frame_bottom, text="删除", command=self.delete)

self.btn_update = tk.Button(self.frame_bottom, text="修改", command=self.update)

self.btn_add = tk.Button(self.frame_bottom, text="添加", command=self.add)

self.btn_delete.grid(row=0, column=0, padx=20, pady=30)

self.btn_update.grid(row=0, column=1, padx=120, pady=30)

self.btn_add.grid(row=0, column=2, padx=30, pady=30)

# 定义中心列表区域

self.tree = ttk.Treeview(self.frame_center, show="headings", height=8, columns=("a", "b", "c", "d"))

self.vbar = ttk.Scrollbar(self.frame_center, orient=tk.VERTICAL, command=self.tree.yview)

# 定义树形结构与滚动条

self.tree.configure(yscrollcommand=self.vbar.set)

# 表格的标题

self.tree.column("a", width=80, anchor="center")

self.tree.column("b", width=120, anchor="center")

self.tree.column("c", width=120, anchor="center")

self.tree.column("d", width=120, anchor="center")

self.tree.heading("a", text="小组编号")

self.tree.heading("b", text="小组名称")

self.tree.heading("c", text="负责人")

self.tree.heading("d", text="联系方式")

# 调用方法获取表格内容插入及树基本属性设置

self.tree["selectmode"] = "browse"

self.get_tree()

self.tree.grid(row=0, column=0, sticky=tk.NSEW, ipadx=10)

self.vbar.grid(row=0, column=1, sticky=tk.NS)

# 定义整体区域

self.frame_top.grid(row=0, column=0, padx=60)

self.frame_center.grid(row=1, column=0, padx=60, ipady=1)

self.frame_bottom.grid(row=2, column=0, padx=60)

self.frame_top.grid_propagate(0)

self.frame_center.grid_propagate(0)

self.frame_bottom.grid_propagate(0)

# 窗体设置

self.center_window(600, 360)

self.title('评议小组管理')

self.resizable(False, False)

self.mainloop()

# 窗体居中

def center_window(self, width, height):

screenwidth = self.winfo_screenwidth()

screenheight = self.winfo_screenheight()

# 宽高及宽高的初始点坐标

size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)

self.geometry(size)

# 数据初始化获取

def init_data(self):

result, _ = self.opr.query()

if self.opr.queryStatus:

return 0

else:

return result

# 表格内容插入

def get_tree(self):

if self.list == 0:

tkinter.messagebox.showinfo("错误提示", "数据获取失败")

else:

# 删除原节点

for _ in map(self.tree.delete, self.tree.get_children("")):

pass

# 更新插入新节点

for i in range(len(self.list)):

group = self.list[i]

self.tree.insert("", "end", values=(group[0],

group[1],

group[2],

group[3]), text=group[0])

# TODO 此处需解决因主程序自动刷新引起的列表项选中后重置的情况,我采用的折中方法是:把选中时的数据保存下来,作为记录

# 绑定列表项单击事件

self.tree.bind("", self.tree_item_click)

self.tree.after(500, self.get_tree)

# 单击查询按钮触发的事件方法

def query(self):

query_info = self.ent_find_name.get()

self.string.set('')

# print(query_info)

if query_info is None or query_info == '':

tkinter.messagebox.showinfo("警告", "查询条件不能为空!")

self.get_tree()

else:

result, _ = self.opr.query(queryby="where name like '%" + query_info + "%'")

self.get_tree()

if self.opr.queryStatus:

tkinter.messagebox.showinfo("警告", "查询出错,请检查数据库服务是否正常")

elif not result:

tkinter.messagebox.showinfo("查询结果", "该查询条件没有匹配项!")

else:

self.list = result

# TODO 此处需要解决弹框后代码列表刷新无法执行的问题

# 单击删除按钮触发的事件方法

def delete(self):

if self.item_selection is None or self.item_selection == '':

tkinter.messagebox.showinfo("删除警告", "未选中待删除值")

else:

# TODO: 删除提示

self.opr.delete(deleteby="no = '"+self.item_selection+"'")

if self.opr.deleteStatus:

tkinter.messagebox.showinfo("删除警告", "删除异常,可能是数据库服务意外关闭了。。。")

else:

self.list = self.init_data()

self.get_tree()

# 为解决窗体自动刷新的问题,记录下单击项的内容

def tree_item_click(self, event):

try:

selection = self.tree.selection()[0]

self.data = self.tree.item(selection, "values")

self.item_selection = self.data[0]

except IndexError:

tkinter.messagebox.showinfo("单击警告", "单击结果范围异常,请重新选择!")

# 单击更新按钮触发的事件方法

def update(self):

if self.item_selection is None or self.item_selection == '':

tkinter.messagebox.showinfo("更新警告", "未选中待更新项")

else:

data = [self.item_selection]

self.data = self.set_info(2)

if self.data is None or not self.data:

return

# 更改参数

data = data + self.data

self.opr.update(updatelist=data)

if self.opr.insertStatus:

tkinter.messagebox.showinfo("更新小组信息警告", "数据异常库连接异常,可能是服务关闭啦~")

# 更新界面,刷新数据

self.list = self.init_data()

self.get_tree()

# 单击新增按钮触发的事件方法

def add(self):

# 接收弹窗的数据

self.data = self.set_info(1)

if self.data is None or not self.data:

return

# 更改参数

self.opr.insert(insertlist=self.data)

if self.opr.insertStatus:

tkinter.messagebox.showinfo("新增小组信息警告", "数据异常库连接异常,可能是服务关闭啦~")

# 更新界面,刷新数据

self.list = self.init_data()

self.get_tree()

# 此方法调用弹窗传递参数,并返回弹窗的结果

def set_info(self, dia_type):

"""

:param dia_type:表示打开的是新增窗口还是更新窗口,新增则参数为1,其余参数为更新

:return: 返回用户填写的数据内容,出现异常则为None

"""

dialog = MyDialog(data=self.data, dia_type=dia_type)

# self.withdraw()

self.wait_window(dialog) # 这一句很重要!!!

return dialog.group_info

# 新增窗口或者更新窗口

class MyDialog(tk.Toplevel):

def __init__(self, data, dia_type):

super().__init__()

# 窗口初始化设置,设置大小,置顶等

self.center_window(600, 360)

self.wm_attributes("-topmost", 1)

self.resizable(False, False)

self.protocol("WM_DELETE_WINDOW", self.donothing) # 此语句用于捕获关闭窗口事件,用一个空方法禁止其窗口关闭。

# 根据参数类别进行初始化

if dia_type == 1:

self.title('新增小组信息')

else:

self.title('更新小组信息')

# 数据变量定义

self.no = tk.StringVar()

self.name = tk.StringVar()

self.pname = tk.StringVar()

self.pnum = tk.StringVar()

if not data or dia_type == 1:

self.no.set('')

self.name.set('')

self.pname.set('')

self.pnum.set('')

else:

self.no.set(data[0])

self.name.set(data[1])

self.pname.set(data[2])

self.pnum.set(data[3])

# 错误提示定义

self.text_error_no = tk.StringVar()

self.text_error_name = tk.StringVar()

self.text_error_pname = tk.StringVar()

self.text_error_pnum = tk.StringVar()

self.error_null = '该项内容不能为空!'

self.error_exsit = '该小组编号已存在!'

self.group_info = []

# 弹窗界面布局

self.setup_ui()

# 窗体布局设置

def setup_ui(self):

# 第一行(两列)

row1 = tk.Frame(self)

row1.grid(row=0, column=0, padx=160, pady=20)

tk.Label(row1, text='小组编号:', width=8).pack(side=tk.LEFT)

tk.Entry(row1, textvariable=self.no, width=20).pack(side=tk.LEFT)

tk.Label(row1, textvariable=self.text_error_no, width=20, fg='red').pack(side=tk.LEFT)

# 第二行

row2 = tk.Frame(self)

row2.grid(row=1, column=0, padx=160, pady=20)

tk.Label(row2, text='小组名称:', width=8).pack(side=tk.LEFT)

tk.Entry(row2, textvariable=self.name, width=20).pack(side=tk.LEFT)

tk.Label(row2, textvariable=self.text_error_name, width=20, fg='red').pack(side=tk.LEFT)

# 第三行

row3 = tk.Frame(self)

row3.grid(row=2, column=0, padx=160, pady=20)

tk.Label(row3, text='负责人姓名:', width=10).pack(side=tk.LEFT)

tk.Entry(row3, textvariable=self.pname, width=18).pack(side=tk.LEFT)

tk.Label(row3, textvariable=self.text_error_pname, width=20, fg='red').pack(side=tk.LEFT)

# 第四行

row4 = tk.Frame(self)

row4.grid(row=3, column=0, padx=160, pady=20)

tk.Label(row4, text='手机号码:', width=8).pack(side=tk.LEFT)

tk.Entry(row4, textvariable=self.pnum, width=20).pack(side=tk.LEFT)

tk.Label(row4, textvariable=self.text_error_pnum, width=20, fg='red').pack(side=tk.LEFT)

# 第五行

row5 = tk.Frame(self)

row5.grid(row=4, column=0, padx=160, pady=20)

tk.Button(row5, text="取消", command=self.cancel).grid(row=0, column=0, padx=60)

tk.Button(row5, text="确定", command=self.ok).grid(row=0, column=1, padx=60)

def center_window(self, width, height):

screenwidth = self.winfo_screenwidth()

screenheight = self.winfo_screenheight()

size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)

self.geometry(size)

# 点击确认按钮绑定事件方法

def ok(self):

self.group_info = [self.no.get(), self.name.get(), self.pname.get(), self.pnum.get()] # 设置数据

if self.check_info() == 1: # 进行数据校验,失败则不关闭窗口

return

self.destroy() # 销毁窗口

# 点击取消按钮绑定事件方法

def cancel(self):

self.group_info = None # 空!

self.destroy()

# 数据校验和用户友好性提示,校验失败返回1,成功返回0

def check_info(self):

is_null = 0

str_tmp = self.group_info

if str_tmp[0] == '':

self.text_error_no.set(self.error_null)

is_null = 1

if str_tmp[1] == '':

self.text_error_name.set(self.error_null)

is_null = 1

if str_tmp[2] == '':

self.text_error_pname.set(self.error_null)

is_null = 1

if str_tmp[3] == '':

self.text_error_pnum.set(self.error_null)

is_null = 1

if is_null == 1:

return 1

res, _ = OracleOpr().query(queryby="where no = '"+str_tmp[0]+"'")

print(res)

if res:

self.text_error_no.set(self.error_exsit)

return 1

return 0

# 空函数

def donothing(self):

pass

guiPy.py

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

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

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

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

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

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

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

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

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

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

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

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

再一波Python实战项目列表

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

Python GUI - tkinter

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

Python开发GUI实战:图片转换素描画工具!

奋斗没有终点 好好学习72变,因为将来 没有人能替你阻挡81难 . 生如蝼蚁,当有鸿鹄之志: 命如纸薄,应有不屈之心 . ​ 今天被这句话触动了,所以开篇分享给大家.鸡汤有毒,但有时大家却靠它激励自己 ...

随机推荐

java 调用 sql server存储过程

Transact-SQL中的存储过程,非常类似于Java语言中的方法,它可以重复调用.当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句.这样就可以提高存储过程的性能. Ø ...

报表session与应用session常识普及

1. 报表session与应用session 报表集成到项目中可能会有一个疑问就是系统应用和报表应用在一个web服务器下,那系统session和报表session是不是一个session呢?如果不是那 ...

“REST”——Representational State Transfer(表述性状态转移)

Representational State Transfer http://www.infoq.com/cn/articles/understanding-restful-style/#anch10 ...

Nginx+Tomcat动静态资源分离

1 创建用户.用户组 useradd -g users www passwd www //设置密码,否则该用户不可用 groupadd -g 888 www //创建用户组 gpasswd -a ww ...

Java阻塞中断和LockSupport

在介绍之前,先抛几个问题. Thread.interrupt()方法和InterruptedException异常的关系?是由interrupt触发产生了InterruptedException异常? ...

CSS 特效 (教程还是英文的好)

Border-radius: create rounded corners with CSS! http://www.css3.info/preview/rounded-border/

the convertion between string and BlobColumn

It's hard to find some samples about the convertion between string and BlobColumn.AddBlobData. It's ...

小程序 wx.getRecorderManager 录音 to 语音识别

微信扫小程序码看调用效果(自然语言理解小助手) 欢迎转载,请保留原文链接:http://www.happycxz.com/m/?p=125 这次主要是把我的api更新了一下,支持微信小程序新的录音接口 ...

Docker for Web Developers目录

在OpenStack在私有云占主导定位之后,后起之秀Docker在PaaS平台.CI/CD.微服务领域展露锋芒.作为Web Developers,我们有必要学习和掌握这门技术. 1. 运行第一个Doc ...

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值