Tkinter
文档
使用清华镜像源安装:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tkinter
需求
之前使用pyton编写了一个etl工具,但是使用命令行的形式来操作的,后面感觉这个不是很方便,尝试着做成GUI的形式,因为python有很多种gui库,比如:Tkinter
、wxPython
、Jython
、pyqt5
等,一开始也不知道选哪个,后面发现Tkinter
是官方自带的比较轻量的,因为容易上手,所以就选择了Tkinter
。
因为数据的导入导出涉及到业务,所以这里的例子就用另外一种例子来代替。
比如:我们想要一个实现,首先有两个按钮"开始、"暂停",下方有一个"文本框",当点击"开始","开始"按钮被禁用,然后文本框开始输出当前时间的字符串,点击"暂停","文本框"停止输出。再次点击"开始","文本框"继续输出。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import threading
from tkinter import *
THREAD_RUNNING = False # 工作线程是否在运行的标志位
THREAD_GLOBAL_FLAG = True # 线程种的循环标志位
RUN_FLAG = True # 线程中业务循环执行标志位
def increase(text):
global RUN_FLAG
global THREAD_GLOBAL_FLAG
"""
启动一个线程刷新文本框,因为单线程会阻塞tkinter的gui刷新
:param text:
:return:
"""
curr_table_name = "" # 当前表名
while THREAD_GLOBAL_FLAG:
while RUN_FLAG:
text.config(state=NORMAL)
text.insert('end', "{}
".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
text.see("end")
text.config(state=DISABLED) # 禁止编辑
time.sleep(1)
def bt_method_start(event, bt_start=None, bt_pause=None, text=None):
"""
开始按钮点击事件
:param event: 当前事件
:param bt_start: 开始按钮对象
:param bt_pause: 暂停按钮对象
:param text: 文本框对象
:return:
"""
print("bt_method_start")
global RUN_FLAG
RUN_FLAG = True
bt_start['state'] = 'disabled'
bt_pause['state'] = 'normal'
# 启动线程
global THREAD_RUNNING
if not THREAD_RUNNING:
THREAD_RUNNING = True
t = threading.Thread(target=increase, args=(text,))
t.start()
def bt_method_pause(event, bt_start=None, bt_pause=None, text=None):
"""
暂停按钮点击事件
:param event: 当前事件
:param bt_start: 开始按钮对象
:param bt_pause: 暂停按钮对象
:param text: 文本框对象
:return:
"""
print("bt_method_pause")
global RUN_FLAG
RUN_FLAG = False
bt_start['state'] = 'normal'
bt_pause['state'] = 'disabled'
def on_closing(root):
"""
关闭窗口事件,在这里做清理工作,线程运行标志位修改
:param root:
:return:
"""
print("窗口关闭!")
global RUN_FLAG
global THREAD_GLOBAL_FLAG
RUN_FLAG = False
THREAD_GLOBAL_FLAG = False
print(root)
root.destroy()
def main():
root = Tk()
root.title("窗口")
root.resizable(0, 0) # 阻止Python GUI的大小调整
# 注意此处调用lambda没有参数
# 因为默认的绑定事件等号右边给的是函数名,这种情况没法传递参数,所以使用lambda表达式间接的传递参数
root.protocol("WM_DELETE_WINDOW", lambda : on_closing(root))
# 窗口居中显示,大小为当前屏幕的50%
sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
init_width = int(sw * 0.5)
init_height = int(sh * 0.5)
init_x = int((sw - init_width)/2)
init_y = int((sh - init_height)/2)
root.geometry('{}x{}+{}+{}'.format(init_width, init_height, init_x, init_y)) # 这里的乘是小x
root.update() # 刷新窗口大小,方便下面获得最新的窗口宽高
# print(root.winfo_width())
# print(root.winfo_height())
# print(root.winfo_screenwidth())
# print(root.winfo_screenheight())
# 主框架
app = Frame(root)
app.pack()
# 按钮区域
frame_button = Frame(app)
frame_button.pack(side="top")
# 两个按钮
bt_start = Button(frame_button, width=12, height=1)
bt_start["text"] = "同步"
# bt_start["command"] = bt_method
# bt_start.bind("<Button-1>", bt_method_start) # 绑定单击事件
# bt_start.pack(side="left")
bt_start.grid(column=0, row=0, padx=10, pady=10, ipadx=10, ipady=10)
bt_pause = Button(frame_button, width=12, height=1)
bt_pause["text"] = "暂停"
# bt_pause["command"] = bt_method
# bt_pause.bind("<Button-1>", bt_method_pause) # 绑定单击事件
# bt_pause.pack(side="right")
bt_pause.grid(column=1, row=0, padx=10, pady=10, ipadx=10, ipady=10)
# 显示区域
frame_show = Frame(app)
frame_show.pack(side="top", padx=5, pady=5 ,ipadx=5, ipady=5)
# 创建滚动条
scroll = Scrollbar(frame_show)
# 将滚动条填充
scroll.pack(side=RIGHT, fill=Y) # side是滚动条放置的位置,上下左右。fill是将滚动条沿着y轴填充
# 显示文字区域
text_show = Text(frame_show)
text_show.pack(side=LEFT, fill=Y)
# 插入初始值
text_show.insert('end', '你好,欢迎使用!
')
text_show.config(state=DISABLED) # 禁止编辑
# 将滚动条与文本框关联
scroll.config(command=text_show.yview) # 将文本框关联到滚动条上,滚动条滑动,文本框跟随滑动
text_show.config(yscrollcommand=scroll.set) # 将滚动条关联到文本框
# 使用 lambda 匿名函数绑定监听控件
bt_start.bind("<Button-1>", lambda event: bt_method_start(event, bt_start, bt_pause, text_show)) # 绑定单击事件
bt_pause.bind("<Button-1>", lambda event: bt_method_pause(event, bt_start, bt_pause, text_show)) # 绑定单击事件
root.mainloop()
if __name__ == '__main__':
main()