tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(四)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(四)

四、工具类

PhotoImage

这个就是原 tkinter 模块的 PhotoImage 类的强化版

仍是只支持 png 和 gif 格式的图片,但可以很好的处理 gif 的格式,且提供对 png 图片的缩放操作

参数说明

PhotoImage(file: str | bytes, **kw)

① file: 文件路径,和原 tkinter 模块里的 PhotoImage 一样的参数

② **kw: 其他参数,为了兼容原 tkinter 模块里的 PhotoImage 的其他参数

实例方法

① parse

parse()

用于解析动图,没有参数,返回一个生成器(Generator)

② play

1. play(canvas: Canvas,
2. id,  # type: tkinter._CanvasItemId
3.      interval: int)

用于播放动图(播放条件:canvas 的 lock 属性的值为 True)

① canvas: 播放动画的画布

② id: 播放动画的 _CanvasItemId(就是 create_text 的返回值)

③ interval: 每帧动画的间隔时间(单位:毫秒)

③ zoom

zoom(rate_x: float, rate_y: float, precision: float = 1)

缩放图片(目前返回值为原 tkinter 的 PhotoImage 类)


暂时只支持对 png 格式图片的缩放,gif 格式的仍在测试中……


① rate_x: 横向缩放倍率


② rate_y: 纵向缩放倍率


③ precision: 精度到小数点后的位数,越大运算就越慢

详细用法

如果是 png 格式的图片,用法和原 tkinter 模块里的 PhotoImage 用法一模一样,没有任何改变,主要是对 gif 格式图片有所改变。


首先是,读取 gif 格式的图片时,不需要再写 format 参数了,自动读取并解析每一帧的动画。先实例化一个 gif 格式的图片的 PhotoImage 类,然后再解析它,可以一次性解析它全部的帧数,但考虑到大的动图解析很慢,所以就将解析方法的返回值改成了生成器,以便在外部用协程的方式去迭代它,以实现进度条的功能。这里说的很抽象,具体看下面的示例。

动图播放

上述效果的源代码:

import tkintertools
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540, bg='black')
canvas.place(x=0, y=0)
# 用来播放动图的 _CanvasItemId
background = canvas.create_image(480, 270)
# 创建 PhotoImage 类
image = tkintertools.PhotoImage('background.gif')
# 解析每一帧的图片
for i in image.parse():
    # 每次读取的返回值为当前已解析的帧数
    print(i)
# 播放动图
image.play(canvas, background, 70)
root.mainloop()

上述代码执行后并不是立刻就会弹出窗口的,因为它此时正在解析,在命令行上会看到打印出的当前已解析的帧数。解析完后窗口会立刻弹出并播放动图。


解析的方法设计成这样,一是避免解析大动图(帧数很多)时造成卡顿,二是可以实现进度条的效果,实时查看解析的进度,这样当我们在写大项目的时候,一开始要解析很多动图时,就可以这样把所有的动图整合起来,一次性加载,顺便搞个进度条。而且!最重要的是!这样加载动图并实现进度条的功能,是不需要多线程的参与的!实现这些的功能是最简单的协程 —— yield 关键字!


当然了,也可以用错误捕捉加上 next 函数去迭代生成器以实现进度条的功能:

进度条

上述产生进度条的源代码:

import tkintertools
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540, bg='black')
canvas.place(x=0, y=0)
# 用来播放动图的 _CanvasItemId
background = canvas.create_image(480, 270)
# 创建 PhotoImage 类
image = tkintertools.PhotoImage('background.gif')
# 创建生成器
generator = image.parse()
# 创建进度条
canvas.create_rectangle(60, 450, 900, 480, outline='orange', width=2)
bar = canvas.create_rectangle(60, 450, 60, 480, width=0, fill='lightgreen')
def load():
    """ 加载函数 """
    try:
        # 解析下一帧
        i = next(generator)
        # 修改进度条的长度
        canvas.coords(bar, 60, 450, 60 + i * 20, 480)
        # 再次执行该函数,间隔1毫秒
        root.after(1, load)
    except:
        # 播放动图
        image.play(canvas, background, 70)
load()
root.mainloop()

关于缩放,那就很简单了嘛,但是!你可以去网上找找,看看有没有不用 PIL 库就可以实现缩放图片的,我曾经找过,几乎没有!然鹅,我这里在不引入第三方库的情况下,实现了!虽然在计算速度上可能比 PIL 库稍差一点,但是也足以满足我们的需求!


回到缩放的方法上,precision 参数可以是浮点数,默认为 1,那么缩放的倍率呢就支持到小数点后一位,多了也不精准。顺便一提,将 precision 提升至 2 的话,计算量和计算时间会增长 10 倍!因此,若非对精度有很高的要求,建议把 precision 设在 1.5 以下为好。


这里还要附加地说明一个缺点,这个缺点不是我这个模块造成的,而是原 tkinter 模块就有这个缺陷。就是原 tkinter 的 PhotoImage 的示例对象必须是全局变量的情况下,才能显示其图片,否则只是一片空白,所以用 zoom 进行缩放后得到的图片,记得要“全局化”后再调用!

五、功能函数

1、move_widget

控件移动函数

以特定方式移动由 Place 布局的某个控件或某些控件的集合或图像

参数说明

move_widget(master: Tk | Canvas | tkinter.Misc | tkinter.BaseWidget,
            widget: Canvas | _BaseWidget | tkinter.BaseWidget,
            dx: int,
            dy: int,
            times: int,
            mode: # type: Literal['smooth', 'rebound', 'flat'] | tuple[function, float, float]
)

master: 控件所在的父控件


widget: 要移动位置的控件


dx: 横向移动的距离(单位:像素)


dy: 纵向移动的距离


times: 移动总时长(单位:秒)


mode: 模式,可选三种


       smooth: 速度先慢后快再慢(Sin函数模式,0~π)


       rebound: 和 smooth 一样,但是最后会回弹一下(Cos函数模式,0~0.6π)


       flat: 匀速平移


或者为一个元组的形式:(移动函数, 起始值,终止值)

详细用法

这个函数不仅仅可以对本模块的控件产生效果,对所有原 tkinter 模块的控件也有同样的效果。

有了它,我们可以很轻松的实现以下效果:(鼠标左键按下弹出提示框)

【默认外观】

默认外观-提示框

源代码:

import tkintertools
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540)
canvas.place(x=0, y=0)
def callback():
    """ 键盘关联函数 """
    tip = tkintertools.CanvasLabel(canvas, 700, 550, 250, 100, 0, '— 提示 —\n恭喜你!\n账号登录成功!')
    tkintertools.move_widget(canvas, tip, 0, -120, 0.3, 'rebound')
# 按下鼠标左键执行关联函数(当然,其他函数的触发方式也可)
root.bind('<Button-1>', lambda _: callback())
root.mainloop()

【换上皮肤】

换上皮肤-提示框

源代码:

import tkintertools
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540)
canvas.place(x=0, y=0)
background = tkintertools.PhotoImage('background.png')
canvas.create_image(480, 270, image=background)
def callback():
    """ 键盘关联函数 """
    tip = tkintertools.CanvasLabel(canvas, 700, 550, 250, 100, 0, '— 提示 —\n恭喜你!\n账号登录成功!',
                                   color_fill=tkintertools.COLOR_NONE,
                                   color_text=('grey', 'white', ''),
                                   color_outline=('grey', 'white', ''))
    tkintertools.move_widget(canvas, tip, 0, -120, 0.3, 'rebound')
# 按下鼠标左键执行关联函数(当然,其他函数的触发方式也可)
root.bind('<Button-1>', lambda _: callback())
root.mainloop()

同样的道理,我们也可以让它在适当的时候,再收回去,然后删除它以释放内存。这样,一个提示框的功能就轻易实现了!

又或者我们可以实现一个界面切换的操作界面切换

上述例子的源代码:

import tkintertools
root = tkintertools.Tk('界面切换', geometry='960x540')
canvas_1 = tkintertools.Canvas(root, 960, 540, bg='lightgreen')
canvas_2 = tkintertools.Canvas(root, 960, 540, bg='skyblue')
canvas_1.place(x=0, y=0)
canvas_2.place(x=960, y=0)
tkintertools.CanvasButton(
    canvas_1, 830, 500, 120, 30, 5, '切换界面',
    command=lambda: (tkintertools.move_widget(root, canvas_1, -960, 0, 0.25, 'smooth'),
                     tkintertools.move_widget(root, canvas_2, -960, 0, 0.25, 'smooth')))
tkintertools.CanvasButton(
    canvas_2, 10, 500, 120, 30, 5, '切回界面',
    command=lambda: (tkintertools.move_widget(root, canvas_1, 960, 0, 0.25, 'smooth'),
                     tkintertools.move_widget(root, canvas_2, 960, 0, 0.25, 'smooth')))
root.mainloop()

2、correct_text

修正字符串长度

可将目标字符串改为目标长度并以某种方式对齐

参数说明

1. correct_text(length: int, 
2.              string: str, 
3.              position: Literal['left', 'center', 'right'] = 'center')

length: 目标长度

string: 要修改的字符串

position: 文本处于该长度范围的位置,可选靠左、居中、靠右三个值

       left: 文本靠左

       center: 文本居中

       right: 文本靠右

详细用法

这个就很简单了,一般用于多行文本和单行多个文本之间的对齐,直接给出一个示例吧。

1. print(tkintertools.correct_text(20, '这是个文本'))
2. """ 输出
3.     tkintertools    #到这里截止
4. """

实战中就是像下面这样的:

correct_text 详细用法

这里每一列的文本长度都不是一定,所以就用 correct_text 函数改变它们的长度,并让其居中以达到对齐的效果。

3、change_color

颜色处理函数

按一定比率给出已有 RGB 颜色字符串的渐变 RGB 颜色字符串或其对比色

change_color(color: tuple[str, str] | list[str, str] | str, proportion: float = 1)

color: 颜色元组 (要修改的颜色, 目标颜色),或者一个颜色(返回其对比色)

proportion: 改变比率,默认为 1

详细用法

这个很简单,就是按着参数的来就行,下面给个实例:                                                 渐变色的效果

效果展示的代码:

import tkintertools
from math import sin, pi
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540)
canvas.place(x=0, y=0)
for i in range(700):
    canvas.create_line(
        (100 + i) * canvas.rate_x,
        100 * canvas.rate_x,
        (100 + i) * canvas.rate_x,
        400 * canvas.rate_y,
        fill=tkintertools.change_color(('#0000FF', '#00FF00'), sin(pi*i/700)), width=2)
root.mainloop()

更加逼真的效果:

逼真的渐变色

怎么样?看起来是不是有内味儿了?源代码在下面:

import tkintertools
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540, bg='white')
canvas.place(x=0, y=0)
for i in range(200):
    color = tkintertools.change_color(('#FFFFFF', '#000000'), i/200)
    canvas.create_oval(200 - i/2, 200 - i/2, 300 + i, 300 + i, outline=color, width=2)
root.mainloop()

又或者说,我们可以用这个渐变色啊,干点好玩的事情……

变幻色按钮

上面骚操作的源代码如下:

import tkintertools
from random import randint
root = tkintertools.Tk('tkinter辅助模块操作说明', '960x540')
canvas = tkintertools.Canvas(root, 960, 540)
canvas.place(x=0, y=0)
def colorful(ind=0, color=[None, '#F1F1F1']):
    """ 颜色变幻函数 """
    if not ind:
        color[0], color[1] = color[1], '#%06X' % randint(0, 1 << 24)
    colorful_button.color_fill[0] = tkintertools.change_color(color, ind)
    colorful_button.state()  # 更新按钮外观
    root.after(10, colorful, 0 if ind >= 1 else ind+0.01)
colorful_button = tkintertools.CanvasButton(
    canvas, 100, 100, 120, 30, 0, '颜色变幻', command=colorful)
root.mainloop()

后记

看了这么多,你了解到这个辅助模块有多强大了么?它基本上只用原 tkinter 模块(typing 只用来进行类型提示,sys 只用来检测 Python 版本)就做出了这些功能,不知道是否让你满意呢?如果你认为可以,那是否可以为我点一个小小的赞呢?

目录
相关文章
|
7月前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch基础之模型保存与重载模块、可视化模块讲解(附源码)
PyTorch基础之模型保存与重载模块、可视化模块讲解(附源码)
166 1
|
7月前
|
机器学习/深度学习 并行计算 算法
OpenCV简介、导入及图像处理基础方法讲解(图文解释 附源码)
OpenCV简介、导入及图像处理基础方法讲解(图文解释 附源码)
154 0
|
数据安全/隐私保护 Python
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(三)
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(三)
340 0
|
前端开发 Python 容器
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(一)
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(一)
213 0
|
前端开发 Python 容器
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(二)
tkinter 模块的最强辅助模块 —— tkintertools(万字详解)(二)
233 0
|
Python 容器
Python Qt GUI设计:QMdiArea和QMdiSubWindow类实现多文档界面(拓展篇—3)
一个典型的GUI应用程序可能有多个窗口,选项卡控件和堆栈窗口控件允许一次使用其中的一个窗口。然而,很多时候这种方法不是很有用,因为其他窗口的视图是隐藏的一种同时显示多个窗口的方法是,创建多个独立的窗口,这些独立的窗口被称为SDI(Single Document Interface,单文档界面),每个窗口都可以有自己的菜单系统、工具栏等。这需要占用较多的内存资源。
|
Python
Python Tkinter 教程(四)—— 子模块 messagebox、colorchooser 以及 filedialog 的使用及技巧(万字详解)(上)
Python Tkinter 教程(四)—— 子模块 messagebox、colorchooser 以及 filedialog 的使用及技巧(万字详解)(上)
277 0
|
Python
Python Tkinter 教程(四)—— 子模块 messagebox、colorchooser 以及 filedialog 的使用及技巧(万字详解)(下)
Python Tkinter 教程(四)—— 子模块 messagebox、colorchooser 以及 filedialog 的使用及技巧(万字详解)(下)
331 0
|
机器学习/深度学习 数据可视化 数据挖掘
深度之眼(十四)——Python:文件、异常和模块(下)
深度之眼(十四)——Python:文件、异常和模块(下)
101 0
深度之眼(十四)——Python:文件、异常和模块(下)
|
存储 JSON 编解码
深度之眼(十四)——Python:文件、异常和模块
深度之眼(十四)——Python:文件、异常和模块
156 0
深度之眼(十四)——Python:文件、异常和模块