以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/B1hH5Qzd2RkAiiUId1tLWw

本文大概 2874 个字,阅读需花 10 分钟
内容不多,但也花了一些精力
如要交流,欢迎关注我然后评论区留言
谢谢你的点赞收藏分享

进入正文之前先说一件小事,本公众号已改名为【ENG八戒】,原名是【englyf】。改名的理由是什么?以后会告诉朋友们的!

另外文末有福利彩蛋,毕竟今天是元宵节!


这篇文章属于系列文章《Python 内置界面开发框架 Tkinter入门篇》的第三篇,上接《Python 内置界面开发框架 Tkinter入门篇 乙》,欢迎关注我的微信公众号「ENG八戒」查看这个系列相关文章。

界面布局

关于 Tkinter 框架的 GUI 布局,其实官方没有提供对应的图形化工具可用,但是网上有一些开源的小工具可以使用。这里不打算介绍这些小工具的使用,而是直接用框架提供的几何图形管理器来布局,比如上面提到过的 pack() 就是其中一种。这里提到的几何图形管理器也就是其它框架里常说的布局管理器。

Tkinter 框架提供的布局管理器有:pack、grid、place 三种。每一个控件只可以使用一种布局管理器,不同控件使用的布局管理器可以不一样。

pack

形象点说, pack 就是把控件包装在一个矩形区域,这个区域大小足够放置控件,而且默认置中。pack 是最简单的布局管理器,也称之为包装布局。

直接试一试用 pack 来布局三个静态标签 Label,默认设置(pack() 传入参数为空)

import tkinter as tk

window = tk.Tk()
lbl_1 = tk.Label(
master=window,
text="label 1",
fg="black",
bg="red",
width=10,
height=5
)
lbl_1.pack()
lbl_2 = tk.Label(
master=window,
text="label 2",
fg="black",
bg="yellow",
width=10,
height=5
)
lbl_2.pack()
lbl_3 = tk.Label(
master=window,
text="label 3",
fg="black",
bg="blue",
width=10,
height=5
)
lbl_3.pack()
window.mainloop()

看看显示效果

可以看到,默认 pack 会在父窗口 window 中垂直方向按顺序包装排列这三个静态标签 Label。

那么,如果我需要让这几个标签水平排列呢?可以这样子改

lbl_1.pack(side=tk.LEFT)
...
lbl_2.pack(side=tk.LEFT)
...
lbl_3.pack(side=tk.LEFT)

看看显示效果

pack(side=tk.TOP) 和默认设置等价。

简单汇总介绍一下其它的参数

参数 赋值 说明
after 控件 widget 将此控件包装在控件 widget 后边
anchor NSEW (or subset) 根据方向定位此控件,NSEW 表示北南东西四个方向
before 控件 widget 将此控件包装在控件 widget 前边
expand bool 类型值 跟着父控件一起伸缩
fill NONE、X、Y、BOTH 选择当控件伸缩时按照哪个方向填充
ipadx amount 在x方向添加内部填充
ipady amount 在y方向添加内部填充
padx amount 在x方向添加填充
pady amount 在y方向添加填充
side TOP、BOTTOM、LEFT、RIGHT 把控件往哪边添加

很多时候开发界面都需要让里边的控件跟随窗口自动拉伸大小,来看一下上面的代码应该怎么改

lbl_1.pack(fill=tk.BOTH, expand=tk.TRUE)
...
lbl_2.pack(fill=tk.BOTH, expand=tk.TRUE)
...
lbl_3.pack(fill=tk.BOTH, expand=tk.TRUE)

启动的时候,还没有拉伸窗口

然后拉伸看看

grid

如名字表述,grid 会把父窗口划分成行列,然后根据调用时传入参数 row,column 确定把控件放置在对应的行列中。grid 也称之为格子布局。

还是以静态标签为例,创建 3x3 的矩阵标签。为了凸显各个标签的边界,这里还需要添加 Frame 控件,每个标签放置于单独的 Frame 中。

import tkinter as tk

window = tk.Tk()

for i in range(3):
for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(
master=frame,
text=f"Row {i}\nColumn {j}"
)
label.pack() window.mainloop()

可以看到,上面这个例子布局时,只有 Frame 才需要应用 grid 管理器,因为每个标签和 Frame 一一对应,所以标签不需要重复应用格子布局。

看看显示效果

简单汇总介绍一下其它的参数

参数 赋值 说明
column 列序号 指定放置的列,从0开始
columnspan 列数 放置的控件横跨多少列
ipadx amount 在 x 方向添加内部填充
ipady amount 在 y 方向添加内部填充
padx amount 在 x 方向添加外部填充
pady amount 在 y 方向添加外部填充
row 行序号 指定放置的行,从0开始
rowspan number 放置的控件横跨多少行
sticky NSEW 如果单元格比较大,那么控件的指定边界将贴着单元格。NSEW分别对应顶部、底部、右边、左边边界

细心的朋友会发现,一旦拉伸上面的那个矩阵标签窗口,窗口界面就会露出部分底面,矩阵标签没有跟随一起拉伸。

这样明显和我们的预期不符合,这个问题怎么解决呢?

可以调用父窗口的 columnconfigure() 和 rowconfigure() 方法配置各列和行的伸缩比。这两个方法都有三个输入参数,看下面的表格

参数 说明
index 序号,指定特定的行或列,可以是单个行列序号值,也可以是代表多个行或列的列表
weight 伸缩权重
minsize 最小宽度值

现在来看看怎么改,才能让矩阵标签跟随父窗口一起拉伸?

import tkinter as tk

window = tk.Tk()

for i in range(3):
window.rowconfigure(i, weight=1)
window.columnconfigure(i, weight=1) for j in range(3):
frame = tk.Frame(
master=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=i, column=j)
label = tk.Label(
master=frame,
text=f"Row {i}\nColumn {j}"
)
label.pack() window.mainloop()

看看拉伸之后的显示效果

perfect!另外需要提一下,grid 具有 pack 能做的所有功能,但是使用的形式更简单,因此应该作为更优先的布局管理器。

place

place 用于对控件精确定位的场合。使用的时候需要传入参数 x 和 y 分别用于指定控件的放置位置坐标值 x 和 y,传入的 x 和 y 是基于父控件的左上角为原点的坐标系,单位是像素点。

大多数界面应用里,控件都不需要精确的定位。但是某些,比如地图应用里,就的确需要对元素的精确定位了。

下面举个栗子,在窗口里不同位置放置各一个标签

import tkinter as tk

window = tk.Tk()

label1 = tk.Label(
master=window,
text="place (0, 0)",
bg="yellow"
)
label1.place(x=0, y=0) label2 = tk.Label(
master=window,
text="place (40, 40)",
bg="blue"
)
label2.place(x=40, y=40) window.mainloop()

看看上面代码的显示效果

说回来,place 的参数xy单位是像素,那么在不同的系统下,字体类型和大小都是不同的,那么被放置的控件就有可能超出窗口边界。因此 place 真的不常用,关于 place 进一步的信息就不再展开了。

交互

上面介绍的内容都仅限于 Tkinter 界面的可视化设计,那么现在是时候介绍一下Tkinter 界面和用户的互动了。

比如,Tkinter 界面对于事件的响应是怎么发生的?

一般,在 Tkinter 中通过预先绑定事件和响应处理函数,每当事件发生时,主窗口的 mainloop 就会收到事件,然后根据绑定信息,查找到响应处理函数并调用,来达到交互的效果。绑定的通用方法是调用各个控件的 bind()。

比如,下面我们来实现一个简单的键盘响应互动,每次按键按下时就把对应的按键打印出来

import tkinter as tk

def handle_keypress(event):
print(event.char) window = tk.Tk()
window.bind("<Key>", handle_keypress)
window.mainloop()

上面的代码没有添加额外的控件,除了有个空白的主窗口。其中,对主窗口 window 绑定了按键事件 Key 和处理函数 handle_keypress。

调用 bind() 最少要求输入两个参数,一个是形式为 "<event_name>" 的事件,另一个是事件处理函数。

定义处理函数 handle_keypress 时,唯一做的事情是把传入的事件字符打印到标准终端。

每当按下键盘的按键,命令行终端就会输出对应的按键。

但是,对于按钮 Button 来说,点击事件的触发处理可以不需要使用 bind(),仅需要在实例化控件 Button 时,传入处理函数给 command 参数即可,初始化过程会自动绑定 click 事件的响应。

上代码看看

import tkinter as tk

def handle_keypress():
print("clicked") window = tk.Tk()
button = tk.Button(
master=window,
text="click me!",
command=handle_keypress
)
button.pack()
window.mainloop()

运行程序

用鼠标点击一下界面上的按钮,发现终端会输出字符串 clicked


由于篇幅受限,本系列教程还未完结,下一篇《Python 内置界面开发框架 Tkinter入门篇 丁》将在本公众号稍后推送,如果你对此教程有兴趣或者想和我一起交流更多精彩内容,欢迎关注我的微信公众号 【ENG八戒】,等着你哦!

《元宵彩蛋》

闹元宵了,《八戒陪你一起闹元宵2023

Python 内置界面开发框架 Tkinter入门篇 丙(文末有福利彩蛋,今天可是元宵节)的更多相关文章

  1. Python内置函数详解——总结篇

    2个多月来,将3.5版本中的68个内置函数,按顺序逐个进行了自认为详细的解析,现在是时候进行个总结了.为了方便记忆,将这些内置函数进行了如下分类:     数学运算(7个)     类型转换(24个) ...

  2. Python内置GUI模块Tkinter的几点笔记

    组件属性,用法 组件位置 更多

  3. Python内置函数详解-总结篇

    参考链接:http://www.cnblogs.com/sesshoumaru/p/6140987.html

  4. Python入门之 Python内置函数

    Python入门之 Python内置函数 函数就是以功能为导向,一个函数封装一个功能,那么Python将一些常用的功能(比如len)给我们封装成了一个一个的函数,供我们使用,他们不仅效率高(底层都是用 ...

  5. 浅谈Python内置对象类型——数字篇(附py2和py3的区别之一)

    Python是一门面向对象的编程设计语言,程序中每一样东西都可以视为一个对象.Python内置对象可以分为简单类型和容器类型,简单类型主要是数值型数据,而容器类型是可以包含其他对象类型的集体,如序列. ...

  6. Python基础篇【第2篇】: Python内置函数(一)

    Python内置函数 lambda lambda表达式相当于函数体为单个return语句的普通函数的匿名函数.请注意,lambda语法并没有使用return关键字.开发者可以在任何可以使用函数引用的位 ...

  7. Python之路(第八篇)Python内置函数、zip()、max()、min()

    一.python内置函数 abs() 求绝对值 例子 print(abs(-2)) all() 把序列中每一个元素做布尔运算,如果全部都是true,就返回true, 但是如果是空字符串.空列表也返回t ...

  8. python内置装饰器

    前言 接着上一篇笔记,我们来看看内置装饰器property.staticmethod.classmethod 一.property装饰器 1. 普通方式修改属性值 code class Celsius ...

  9. 几个可以提高工作效率的Python内置小工具

    在这篇文章里,我们将会介绍4个Python解释器自身提供的小工具.这些小工具在笔者的日常工作中经常用到,减少了各种时间的浪费,然而,却很容易被大家忽略.每当有新来的同事看到我这么使用时,都忍不住感叹, ...

  10. 使用Python内置浏览器缓存cookies并做更新

    import requests #python内置的微型浏览器,没有界面的 #作用:缓存cookies s = requests.session() print(s.headers) #伪造请求头部, ...

随机推荐

  1. Graceful Java之try...catch()

    [优美的Java代码之try...catch] 目录 概述 优化 优化前写法(JDK1.7之前) 优化后写法(JDK1.7及以后) 延伸阅读:嵌套的文件流如何正确的关闭 概述 通常我们使用try... ...

  2. OpenFeign

    OpenFeign-服务间的调用 一.什么是Feign和OpenFeign? 在使用Feign或者OpenFeign前,服务之间的调用路径在函数内部设置: 能不能像controller调用servic ...

  3. 2022-11-01 Acwing每日一题

    第k个数 给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k 个数. 输入格式 第一行包含两个整数 n 和 k. 第二行包含 n 个整数(所有整数均在 1 ...

  4. leetcode学习记录2.13

    [13] 罗马数字转整数 import java.util.HashMap; import java.util.Map; /* * * [13] 罗马数字转整数 * * https://leetcod ...

  5. PDF、视频格式缩略图获取(pdf2img)

    PDF.视频格式缩略图获取(pdf2img) 获取pdf缩略图 导入依赖: <dependency> <groupId>org.apache.pdfbox</groupI ...

  6. 第2-4-1章 规则引擎Drools介绍-业务规则管理系统-组件化-中台

    目录 规则引擎 Drools 1. 问题引出 2. 规则引擎概述 2.1 什么是规则引擎 2.2 使用规则引擎的优势 2.3 规则引擎应用场景 2.4 Drools介绍 规则引擎 Drools 全套代 ...

  7. Springboot+Mybatis:启动报错 String index out of range: -37

    springBoot+Druid+Mybatis :启动错误描述 Error parsing SQL Mapper Configuration. Cause: java.lang.StringInde ...

  8. 一行代码实现shell if else逻辑

    前言 前几天学习 shell 脚本,发现这种好用的写法,简单记录一下. if else 一行实现 if [ 1=1 ] ;then echo "条件成立";else echo &q ...

  9. vue3 第二天vue响应式原理以及ref和reactive区别

    前言: 前天我们学了 ref 和 reactive ,提到了响应式数据和 Proxy ,那我们今天就来了解一下,vue3 的响应式 在了解之前,先复习一下之前 vue2 的响应式原理 vue2 的响应 ...

  10. MybatisPlus多表连接查询一对多分页查询数据

    一.序言 在日常一线开发过程中,多表连接查询不可或缺,基于MybatisPlus多表连接查询究竟该如何实现,本文将带你找到答案. 在多表连接查询中,既有查询单条记录的情况,又有列表查询,还有分页查询, ...