Python Tkinter Gui 窗口图标,标签,输入,单复选,文件导入,按钮,日志 等常用组件 基本使用
前言
tkinter是什么?
我们编写的Python代码会调用内置的Tkinter,Tkinter封装了访问Tk的接口; Tk是一个图形库,支持多个操作系统,使用Tcl语言开发; Tk会调用操作系统提供的本地GUI接口,完成最终的GUI;
tkinter库简介
python内置的GUI库,只要安装好 Python 环境之后就能 import tkinter 库; 基于Tk工具包,该工具包最初是为TCL设计的,后被应用到多种脚本语言中,使脚本语言可以开发出品质较好的GUI应用,tkinter是用python做的一个调用接口,底层使用C++编写,运行效率上与C++编写的GUI应用相当,但是开发效率远远高于C++;
本文思路:先介绍窗体以及组件的方法和属性,最后附上示例代码供大家参考
一、窗体设置方法
1.tk类对象的方法
Tk类常用方法 | 描述 |
---|
title() | 设置窗体标题 | iconbitmap() | 设置窗体logo,建议写绝对路径 | geometry() | 设置窗体大小,单位是像素 | attributes(“-topmost”, 1) | 窗体设为置顶 (显示为当前活动窗口) | protocol(‘WM_DELETE_WINDOW’, lambda: clos_window() | 设置右上角(X)点击事件,退出/关闭窗体 | destroy() | 直接退出/关闭窗体 | winfo_screenwidth() | 获取屏幕宽度 | winfo_screenheight() | 获取屏幕高度 | mainloop() | 界面循环,即是显示窗体变化 |
二、常用组件以及公共属性介绍
1.常用组件
组件类 | 名称 | 描述 |
---|
Button | 按钮 | 一个简单的按钮,用来执行一个命令或别的操作,类似标签,但提供额外的功能,例如鼠标掠过、按下、释放以及键盘操作/事件。 | Canvas | 画布 | 组织图形,这个部件可以用来绘制图表和图,创建图形编辑器,实现定制窗口部件,提供绘图功能(直线、椭圆、多边形、矩形) ;可以包含图形或位图 | Checkbutton | 复选框 | 代表一个变量,它有两个不同的值。点击这个按钮将会在这两个值间切换,一组方框,可以选择其中的任意个 | Radiobutton | 单选框 | 一组可选框,其中只有一个可被"选中" ,以当前勾选的值为准 | Entry | 文本框 | 文本输入框,文本输入域 | Frame | 框架/容器 | 归纳组件,用于模块布局,一个容器窗口部件 | Label | 标签 | 用来显示文字或图片 | Listbox | 列表框 | 一个选项列表,用户可以从中选择 | Menu | 菜单 | 点下菜单按钮后弹出的一个选项列表,用户可以从中选择,菜单条,用来实现下拉和弹出式菜单 | Menubutton | 菜单按钮 | 用来包含菜单的组件(有下拉式、层叠式等等) | Scale | 进度条 | 线性“滑块”组件,可设定起始值和结束值,会显示当前位置的精确值 | Scrollbar | 滚动条 | 对其支持的组件(文本域、画布、列表框、文本框)提供滚动功能 | Text | 文本域 | 多行文字区域,可用来收集(或显示)用户输入的文字(类似 HTML 中的 textarea) | ScrolledText | 可滚动文本域 | 常用于日志输出显示 | Toplevel | 顶级 | 类似框架,但提供一个独立的窗口容器 |
2.公共属性
属性/参数 | 描述 |
---|
master | 父窗口指针/上级容器(如:TK类对象) | text | 组件标题(部分组件有:Button、Label …) | bd | 组件边框的大小,默认为 2 个像素 | image | 组件上要显示的图片 | font=(‘行楷’, 15, ‘bold’) | 字体,大小,加粗 | fg | 字体颜色 | bg | 背景颜色 | height | 高,单位像素 | width | 宽 | command | (Button)绑定处理事件函数,当按钮被点击时,执行该函数 command=function,如需传参( command=lambda: function(“参数”)) |
三、常用布局摆放方式
1.grid()–>以行和列(网格)形式对控件进行排列,此种方法使用起来较为灵活,推荐此方法
属性/参数 | 描述 |
---|
row | 设置行数 | rowspan | 设置跨行数量,控件实例所跨的行数,默认为 1 行,通过该参数可以合并一列中多个领近单元格 | column | 设置列数 | columnsapn | 设置跨列数量,控件实例所跨的列数,默认为 1 列,通过该参数可以合并一行中多个领近单元格 | ipadx | 设置组件的内部"左右"的间距,单位为像素§,或者厘米?、英寸(i) | ipady | 设置组件的内部"上下"的间距,单位为像素§,或者厘米?、英寸(i) | padx | 设置组件的外部"左右"的间距 ,单位为像素§,或者厘米?、英寸(i) | pady | 设置组件的外部"上下"的间距,单位为像素§,或者厘米?、英寸(i) | sticky | 该属性用来设置控件位于单元格那个方位上,参数值和 anchor 相同,若不设置该参数则控件在单元格内居中 |
2.pack()–>按照控件的添加顺序其进行排列,遗憾的是此方法灵活性较差
属性/参数 | 描述 |
---|
side | 设置组件相对与父组件的摆放位置,组件放置在窗口的哪个位置上,参数值 ‘top’,‘bottom’,‘left’,‘right’。注意,单词小写时需要使用字符串格式,若为大写单词则不必使用字符串格式 | ipadx | 设置组件的内部"左右"的间距,单位为像素§,或者厘米?、英寸(i) | ipady | 设置组件的内部"上下"的间距,单位为像素§,或者厘米?、英寸(i) | padx | 设置组件的外部"左右"的间距 ,单位为像素§,或者厘米?、英寸(i) | pady | 设置组件的外部"上下"的间距,单位为像素§,或者厘米?、英寸(i) |
3.place()–>(x,y)定位摆放,可以指定组件大小以及摆放位置,三个方法中最为灵活的布局方法
属性/参数 | 描述 |
---|
anchor | 定义控件在窗体内的方位,参数值N/NE/E/SE/S/SW/W/NW 或 CENTER,默认值是 NW | x、y | 定义控件在根窗体中水平和垂直方向上的起始绝对位置,(单位为像素),绝对定位 | height、width | 控件自身的高度和宽度(单位为像素),绝对定位 | relx | 设置距离左上角的水平长度百分比(0-1),相对定位 | rely | 设置距离左上角的垂直高度百分比 ,相对定位 | relwidth | 设置组件所占据的宽度百分比 ,相对定位 | relheight | 设置组件所占据的高度百分比 ,相对定位 |
四、示例代码
1.打包(exe)后的环境资源访问
import os
import sys
""" 判断是否为打包(exe)后的环境 """
if getattr(sys, 'frozen', False):
base_path = sys._MEIPASS
else:
base_path = os.path.abspath(".")
file_path = os.path.join(base_path, "xxxxxxx")
2.完整代码
示例说明:引用了线程不卡顿,滚动文本域实时更新日志,建议复制代码运行仔细观察一下有助于理解 该示例使用了grid()网格布局,输入组件,标签组件,文件选择组件,单选框组件,复选框组件,按钮,滚动文本域,大部分都写了注释哈;
import sys
import time
import tkinter as tk
from tkinter import messagebox
from tkinter.messagebox import askyesno
from tkinter.filedialog import askopenfilename # 文件选择
from tkinter.scrolledtext import ScrolledText
import threading
class TestGui(object):
def __init__(self, init_window_name):
self.file_input_dirs = None # 存放文件地址变量
self.init_window_name = init_window_name
self.init_window_name.title("Python Tkinter 常用组件 - 基本使用") # 设置窗口标题
self.init_window_name.geometry('700x400') # 设置窗口大小
self.init_window_name.iconbitmap('resource/test.ico') # 设置窗体左上角logo,建议写绝对路径
self.init_window_name.attributes("-topmost", 1) # tk界面置顶
""" 点击右上角关闭窗体弹窗事件 """
self.init_window_name.protocol('WM_DELETE_WINDOW', self.clos_window)
""" 组件容器创建 """
self.input_frame = tk.Frame(master=self.init_window_name) # 创建存放文本输入,文件选择组件的容器
self.input_frame.grid(padx=20, pady=5, row=1, column=0, sticky=tk.W) # 外间距20px,上下间距0,1行,0(从0开始)列
self.choose_day_frame = tk.Frame(master=self.init_window_name) # 创建存放单选组件的容器
self.choose_day_frame.grid(padx=20, pady=0, row=2, column=0, sticky=tk.W)
self.choose_number_frame = tk.Frame(master=self.init_window_name) # 创建存放复选组件的容器
self.choose_number_frame.grid(padx=20, pady=0, row=3, column=0, sticky=tk.W)
self.log_frame = tk.Frame(master=self.init_window_name) # 创建存放日志组件的容器
self.log_frame.grid(padx=20, pady=0, row=4, column=0, sticky=tk.W)
self.runs_button_frame = tk.Frame(self.init_window_name) # 创建存放日志组件的容器
self.runs_button_frame.grid(padx=20, pady=0, row=5, column=0, sticky=tk.W)
""" 文本输入,文件选择组件 """
self.file_input_title = tk.Label(self.input_frame, text="输入文件地址", font=('行楷', 15))
self.file_input_title.grid(padx=20, pady=0, row=0, column=0, sticky=tk.W)
self.file_input_entry = tk.Entry(self.input_frame, font=('行楷', 20), width=24)
self.file_input_entry.grid(padx=0, pady=0, row=0, column=1)
self.file_input_button = tk.Button(self.input_frame, text="选择文件", font=('行楷', 15), width=12, fg="white", bg="#1E90FF", command=self.file_input_path)
self.file_input_button.grid(padx=10, pady=0, row=0, column=2, sticky=tk.W)
""" 单选框 - 选择日期 """
self.radio_label = tk.Label(self.choose_day_frame, text="单选框:", font=('行楷', 15))
self.radio_label.grid(padx=20, pady=0, row=0, column=1, sticky=tk.W)
self.choose_day_value = tk.StringVar()
self.date_list = ['2022-10-16', '2022-10-17', '2022-10-18', '2022-10-19']
self.choose_day_value.set(0) # 设置默认值 '0'
# 单选组件参数介绍 text=勾选框文本, variable=赋值对象, value=勾选后的值
self.choose_day_one = tk.Radiobutton(self.choose_day_frame, text=self.date_list[0], variable=self.choose_day_value, value=self.date_list[0], font=('行楷', 12))
self.choose_day_one.grid(padx=12, pady=0, row=0, column=2)
self.choose_day_two = tk.Radiobutton(self.choose_day_frame, text=self.date_list[1], variable=self.choose_day_value, value=self.date_list[1], font=('行楷', 12))
self.choose_day_two.grid(padx=12, pady=0, row=0, column=3)
self.choose_day_three = tk.Radiobutton(self.choose_day_frame, text=self.date_list[2], variable=self.choose_day_value, value=self.date_list[2], font=('行楷', 12))
self.choose_day_three.grid(padx=12, pady=0, row=0, column=4)
self.choose_day_four = tk.Radiobutton(self.choose_day_frame, text=self.date_list[3], variable=self.choose_day_value, value=self.date_list[3], font=('行楷', 12))
self.choose_day_four.grid(padx=12, pady=0, row=0, column=5)
""" 复选框 - 选择数字 """
self.check_label = tk.Label(self.choose_number_frame, text="复选框:", font=('行楷', 15))
self.check_label.grid(padx=20, pady=0, row=0, column=1, sticky=tk.W)
self.choose_number_value_one = tk.IntVar()
self.choose_number_value_one.set(0) # 设置默认值 0
self.choose_number_value_two = tk.IntVar()
self.choose_number_value_two.set(0) # 设置默认值 0
self.choose_number_value_three = tk.IntVar()
self.choose_number_value_three.set(0) # 设置默认值 0
# 复选组件参数介绍 text=勾选框文本, variable=赋值对象, onvalue=勾选后的值, offvalue未勾选的值
self.choose_entry_time_one = tk.Checkbutton(self.choose_number_frame, text='1', variable=self.choose_number_value_one, onvalue=1, offvalue=0, font=('行楷', 12))
self.choose_entry_time_one.grid(padx=12, pady=0, row=0, column=2)
self.choose_entry_time_two = tk.Checkbutton(self.choose_number_frame, text="2", variable=self.choose_number_value_two, onvalue=2, offvalue=0, font=('行楷', 12))
self.choose_entry_time_two.grid(padx=12, pady=0, row=0, column=3)
self.choose_entry_time_three = tk.Checkbutton(self.choose_number_frame, text="3", variable=self.choose_number_value_three, onvalue=3, offvalue=0, font=('行楷', 12))
self.choose_entry_time_three.grid(padx=12, pady=0, row=0, column=4)
""" 日志框 """
self.run_log = ScrolledText(self.log_frame, font=('楷体', 13), width=69, height=14)
self.run_log.grid(padx=20, pady=5, row=0, column=0)
""" 操作按钮 """
self.start_run1 = tk.Button(self.runs_button_frame, text='参数打印', font=('行楷', 15, 'bold'), fg="white", bg="#1E90FF", width=16, command=lambda: self.thread_it(self.param_print))
self.start_run1.grid(padx=20, pady=0, row=0, column=1)
self.start_run2 = tk.Button(self.runs_button_frame, text='线程测试打印1', font=('行楷', 15, 'bold'), fg="white", bg="#1E90FF", width=16, command=lambda: self.thread_it(self.print1))
self.start_run2.grid(padx=15, pady=0, row=0, column=2)
self.start_run3 = tk.Button(self.runs_button_frame, text='线程测试打印2', font=('行楷', 15, 'bold'), fg="white", bg="#1E90FF", width=16, command=lambda: self.thread_it(self.print2))
self.start_run3.grid(padx=20, pady=0, row=0, column=3)
def thread_it(self, func, *args):
""" 将函数打包进线程 """
self.myThread = threading.Thread(target=func, args=args)
self.myThread .setDaemon(True) # 主线程退出就直接让子线程跟随退出,不论是否运行完成。
self.myThread .start()
def file_input_path(self):
""" 上传文件路径选择 """
path_ = askopenfilename() # 文件选择方法,目录选择是 from tkinter.filedialog import askdirectory,用法一致
self.file_input_dirs = path_ # 将字符串文件地址给变量
self.file_input_entry.delete(0, tk.END) # 将文本输入组件的信息删除
self.file_input_entry.insert(tk.END, path_) # 在文本输入组件,插入文件导入按钮的字符串地址
def param_print(self):
# 如果输入地址和文件选择按钮的值都为None,则提示
if len(self.file_input_entry.get().strip()) < 1 and self.file_input_dirs is None:
messagebox.showwarning(title='小洲助手v1.1警告', message='必须输入或选择文件地址!')
return False
# 如果输入地址为空则选用文件选择按钮的值
if len(self.file_input_entry.get().strip()) > 1:
file_path = self.file_input_entry.get().strip()
else:
file_path = self.file_input_dirs
file_path_content = f"文件地址为:{file_path}"
# 不勾选单选框则值为初始设置的'0', 赋值None
radio_value = 'None' if self.choose_day_value.get() == '0' else self.choose_day_value.get()
radio_value_content = f"单选值为:{radio_value}"
# 不勾选复选框则值为初始设置的0, 赋值None
check_value_one = 'None' if self.choose_number_value_one.get() == 0 else self.choose_number_value_one.get()
check_value_two = 'None' if self.choose_number_value_two.get() == 0 else self.choose_number_value_two.get()
check_value_three = 'None' if self.choose_number_value_three.get() == 0 else self.choose_number_value_three.get()
check_value_content = f'复选值依次为:{check_value_one}, {check_value_two}, {check_value_three}'
self.run_log_print(file_path_content)
self.run_log_print(radio_value_content)
self.run_log_print(check_value_content) # 日志输出
def print1(self):
for i in range(100):
tip_content = f'第{i}次打印 - 我是小洲1'
self.run_log_print(message=tip_content)
time.sleep(0.05) # 睡眠,单位秒
self.run_log_print(message='我是小洲1 - 打印完成')
def print2(self):
for i in range(100, 200):
tip_content = f'第{i}次打印 - 我是小洲2'
self.run_log_print(message=tip_content)
time.sleep(0.05) # 睡眠
self.run_log_print(message='我是小洲2 - 打印完成')
def run_log_print(self, message):
""" 实时更新日志,固定用法 """
self.run_log.config(state=tk.NORMAL)
self.run_log.insert(tk.END, "\n" + message + "\n")
self.run_log.see(tk.END)
self.run_log.update()
self.run_log.config(state=tk.DISABLED)
def clos_window(self):
""" 退出/关闭窗体 固定方法 """
ans = askyesno(title='小洲助手v1.1警告', message='是否确定退出程序?\n是则退出,否则继续!')
if ans:
self.init_window_name.destroy()
sys.exit()
else:
return None
if __name__ == '__main__':
""" 实例化出一个父窗口 """
init_window = tk.Tk()
""" 创建Gui类对象 """
test_gui = TestGui(init_window)
""" 界面循环,实时显示窗体变化 """
init_window.mainloop()
3.运行效果
总结
C语言中文网Tkinter教程(非常详细):http://c.biancheng.net/tkinter/ 以上就是今天要讲的内容,本文仅仅介绍了Tk制作Gui界面的简单使用,而Tk为我们提供了大量封装程序功能的函数和方法,丰富用户的体验感,后续有关于tk的常用代码会在这篇博客中持续更新。
|