tkintertools-dev


Nametkintertools-dev JSON
Version 2.6.5 PyPI version JSON
download
home_pagehttps://github.com/Xiaokang2022/tkintertools
SummaryAn auxiliary module of the tkinder module
upload_time2023-06-13 06:31:52
maintainer
docs_urlNone
authorXiaokang2022
requires_python>=3.8
licenseMulanPSL-2.0
keywords tkinter tkintertools gui
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">
    <h1>🚀tkintertools🚀</h1>
    <p><img height="128px" alt="logo.png" src="tkt.png" /></p>
    <p>
    The <code>tkintertools</code> module is an auxiliary module of the <code>tkinter</code> module
    <br />
    <code>tkintertools</code> 模块是 <code>tkinter</code> 模块的辅助模块
    </p>
    <p>
        <a href="tkintertools/__init__.py">
            <img src="https://img.shields.io/badge/Version-2.6.5(dev)-blue" alt="latest version" />
        </a>
        <a href="LICENSE">
            <img src="https://img.shields.io/badge/License-Mulan PSL v2-green" alt="License" />
        </a>
        <a href="CHANGELOG.md">
            <img src="https://img.shields.io/badge/ChangeLog-2023/06/13-orange" alt="ChangeLog" />
        </a>
        <a href="TODO.md">
            <img src="https://img.shields.io/badge/ToDo-14-yellow?logo=cachet" alt="ToDos" />
        </a>
        <a href="https://pypistats.org/packages/tkintertools">
            <img src="https://img.shields.io/badge/Download-4k-purple?logo=pypi" alt="Downloads" />
        </a>
        <br />
        <a href="mailto:2951256653@qq.com">
            <img src="https://img.shields.io/badge/Email-2951256653@qq.com-cyan" alt="Email" />
        </a>
        <a href="https://github.com/Xiaokang2022">
            <img src="https://img.shields.io/badge/Author-小康2022-white" alt="Author" />
        </a>
        <a href="https://xiaokang2022.blog.csdn.net">
            <img src="https://img.shields.io/badge/Blog-小康2022@CSDN-red" alt="Blog" />
        </a>
    </p>
</div>

Install/模块安装
---------------

### Stable version/稳定版本

* Version/版本 : 2.6.4
* Release Date/发布日期 : 2023/06/12

这个是目前的最新稳定版,比较稳定,bug (可能)没有那么多,推荐使用这个。  
关于稳定版有 Issue 的话,我会去查看并尝试解决 Issue。

```
pip install tkintertools==2.6.4
```

### Development version/开发版本

* Version/版本 : 2.6.5
* Release Date/发布日期 : 2023/06/13

这个是我正在开发的版本,可能有新功能,bug 也可能会比较多,但也可能会比原来的版本更加稳定。  
大家可以在 Issue 中提出一些建议,我会适当采纳一些并在开发版本中更改或实现。

```
pip install tkintertools-dev==2.6.5
```

**Attention/特别注意**
* 开发版仅作示例,各函数或类的API并非最终确定结果,直接使用开发版可能导致后续无法与正式版兼容!
* 若要使用开发版,请先卸载正式版后再进行pip安装,再次使用正式版时也是一样,先卸载开发版再安装正式版!

### Environmental requirements/环境需求

没有任何额外的依赖包(除了tkinter),但只支持以下 Python 版本:

![Python3.8](https://img.shields.io/badge/Python-3.8.*-blue?logo=python)
![Python3.9](https://img.shields.io/badge/Python-3.9.*-blue?logo=python)
![Python3.10](https://img.shields.io/badge/Python-3.10.*-blue?logo=python)
![Python3.11](https://img.shields.io/badge/Python-3.11.*-blue?logo=python)
![Python3.12](https://img.shields.io/badge/Python-3.12.*-blue?logo=python)

可能在某些操作系统上也可运行,但目前以下操作系统已经测试通过:

![Windows10](https://img.shields.io/badge/Windows-10-green?logo=windows)
![Windows11](https://img.shields.io/badge/Windows-11-green?logo=windows11)
![Ubuntu22.04](https://img.shields.io/badge/Ubuntu-22.04-green?logo=ubuntu)

<a name="news">News/最新功能</a>
------------

最新开发版(2.6.5-dev)新内容:

- [X] 子模块`tools_3d`新增类`Space`可以直接提供对3D对象进行平移、旋转和缩放等操作的功能
- [X] 修复了类`Cuboid`和类`Tetrahedron`没有将实例添加到父类`Canvas_3D`的bug
- [X] 修复了当3D对象出现在相机位置后面时会显示错误的bug
- [X] 修复了部分错误的类型提示

最新稳定版(2.6.4)新内容:

新增了对3d几何体空间位置排序的支持,使得几何体不再只有粗略的线条,而拥有丰富的颜色。

在 Windows 系统下运行下面的示例程序时,其拥有以下功能:
* 按住鼠标左键拖动可以旋转这多个几何体;
* 按住鼠标右键拖动可以移动这些几何体在空间中的位置;
* 按“=”和“-”键分别可以放大和缩小几何体的大小;
* 滚动鼠标中键可以放大和缩小画面。

下面是示例程序的效果图:

![news.png](news.png)

<details><summary><b>源代码</b></summary>

```python
from tkinter import Event

import tkintertools as tkt
from tkintertools import tools_3d as t3d

root = tkt.Tk('tool_3d', 1280, 720)
cv3d = t3d.Canvas_3D(root, 1280, 720, 0, 0)

origin = t3d.Point(cv3d, [0, 0, 0])  # 原点
k = -100, 0, 100
geos = [t3d.Cuboid(cv3d, a-50, b-50, c-50, 100, 100, 100, color_up='white', color_down='yellow', color_left='red',
                   color_right='orange', color_front='blue', color_back='green') for a in k for b in k for c in k]
cv3d.space_sort()


def translate(event, flag=False, _cache=[]):
    # type: (Event, bool, list[float]) -> None
    """ 平移事件 """
    if flag:
        _cache[:] = [event.x, event.y]
        return
    dx = (event.x - _cache[0])
    dy = (event.y - _cache[1])
    _cache[:] = [event.x, event.y]
    for geo in geos:
        geo.translate(0, dx, dy)
        geo.update()
    origin.translate(0, dx, dy)
    origin.update()
    cv3d.space_sort()


def rotate(event, flag=False, _cache=[]):
    # type: (Event, bool, list[float]) -> None
    """ 旋转事件 """
    if flag:
        _cache[:] = [event.x, event.y]
        return
    dy = (event.x - _cache[0]) / 100
    dx = (_cache[1] - event.y) / 100
    _cache[:] = [event.x, event.y]
    for item in geos:
        item.rotate(0, dx, dy, center=origin.coords)
        item.update()
    cv3d.space_sort()


def scale(event):  # type: (Event) -> None
    """ 缩放事件 """
    k = 1.05 if event.keysym == 'equal' else 0.95 if event.keysym == 'minus' else 1
    for geo in geos:
        geo.scale(k, k, k)
        geo.update()
    cv3d.space_sort()


def scale_center(event):  # type: (Event) -> None
    """ 中心缩放事件 """
    k = 1.05 if event.delta > 0 else 0.95
    for geo in geos:
        geo.scale(k, k, k, center=origin.coords)
        geo.update()
    cv3d.space_sort()


root.bind('<Button-1>', lambda event: rotate(event, True))
root.bind('<B1-Motion>', rotate)
root.bind('<Button-3>', lambda event: translate(event, True))
root.bind('<B3-Motion>', translate)
root.bind('<Any-Key>', scale)
root.bind('<MouseWheel>', scale_center)
root.mainloop()
```

</details>

更多更新信息请见:[CHANGELOG.md](CHANGELOG.md)

Description/模块说明
----------------------

tkintertools 是一款基于 tkinter 模块的二次开发的界面编程模块,它完全没有使用任何第三方模块和库的,同时,它也没有任何依赖包,它的功能完全由内置模块和函数实现,而且,它还是跨平台的!它和 tkinter 最大的不同在于,它的控件并非真实的控件,而是在 tkinter 模块中 Canvas 对象中绘制而成的,这就赋予了 tkintertools 控件一些在 tkinter 中没有的特性,列举如下:

* 控件背景可以是透明的(实际上是没有背景颜色)
* 控件的样式可以是自定义的(比如按钮有圆角)
* 控件的创建速度远大于 tkinter 的控件(除了 Canvas 控件)

但同时也产生了一些缺点:

* 虚拟的控件无法获取焦点
* 虚拟的控件在文本输入和显示的功能上存在一些缺陷(这个缺陷不是很明显,但强迫症就有点难受了,比如我)

tkintertools 模块还具有一些特色的功能:

* 利用 tkinter 和 tkintertools 创建的程序,在高分辨率的情况下,tkintertools 的会更加清晰(这点对于笔记本用户很友好,比如我)
* 可以迅速实现渐变色的效果
* 窗口缩放,所有的控件的大小跟着缩放(当然,也可以设置为不跟随缩放)
* 子模块 tools_3d 可以是满足简单的 3D 绘图需求

Provides/模块功能
-------------------

Here, only the more distinctive features will be listed  
这里只会列举出比较具有特色的功能

### Customizable widgets/可自定义的控件

tkintertools 模块的控件拥有许多参数供我们设置,比如圆角的半径、文本和边框以及控件内部的颜色,关联事件等等。  
这里要说明的是,每个控件可以设置的关联事件不止一种,在鼠标经过控件时可以绑定事件,鼠标点击控件也可以,鼠标点击后松开也行等等。  
文本和边框以及控件的填充色也是类似的,在鼠标经过控件、点击控件、点击后松开都可以设定颜色。  
文本类控件还能够从右边逐步输入文本,文本输入提示符也可以不是单调无趣的竖线,可以是其他的,比如下划线等。  
最后,大家可以看一下 [test.py](test.py) 文件里面的示例,这个示例展示了 tkintertools 模块的绝大部分功能,示例中更有隐藏的 “多彩变幻” 彩蛋哦!

### Automatically control size/自动控制大小

tkintertools 中的控件,其大小和形状可以随着窗口的变化而成比例地变化,不仅仅是控件中的文本,Canvas 绘制的图形也会随之变动,更让人兴奋的是,png 类型的图片也会随之成比例地缩放!当然,你也可以设定参数让其不随之变动,也可以设定参数使其在缩放的时候保持横纵方向的比例。  
总之,很方便,很舒适!

### Easily move widgets/轻松移动控件

见 [移动函数](#move)

### Gradient colors/渐变色

见 [颜色函数](#Gradient)

### Automatically adapt to DPI/自动适应DPI

见 [DPI 级别设置函数](#DPI)

### Detailed type hints/详细的类型提示

参考 [PEP 526](https://peps.python.org/pep-0526/)、[PEP 586](https://peps.python.org/pep-0586/)、[PEP 604](https://peps.python.org/pep-0604/) 和 [PEP 612](https://peps.python.org/pep-0612/),我采用了最兼容的方式去实现详细的类型提示,可适用 IDE 有 VScode、Pycharm 等。  
那什么是类型提示呢?话不多说,直接看图就行:

![type_hint.png](readme_res/type_hint_vscode.png)

在 VSCode 编辑器中,当鼠标移至类或者函数的名字上面时,会自动显示该类或者函数的注释文档。通过这种方式,不需要看太多的帮助文档和资料就能熟练地使用 tkintertools 模块!

### Across Platforms/跨平台

[test.py](test.py) 在 Windows 系统(**Windows10**)上运行的界面如下:

![test_windows10.png](readme_res/test_windows10.png)

[test.py](test.py) 在 Linux 系统(**Ubuntu22.04**)上运行的界面如下:

![test_linux.png](readme_res/test_linux.png)

[test.py](test.py) 在 Windows 系统(**Windows11**)上运行的界面如下(智能控制圆角半径):

![test_windows11.png](readme_res/test_windows11.png)

### 3D Drawing/3D绘图

见 [News/最新功能](#news)

Contents/模块内容
-------------------

Each non internal class and function in the module will be described in detail here  
这里会详细说明模块中的每个非内部类和函数

### Container Widget/容器控件

1. `Tk`: 窗口类

    继承于`tkinter.Tk`,在继承了`tkinter`模块内`Tk`的基础上,又加入了对`tkintertools`模块中的`Canvas`对象的支持,并加入了检测窗口大小是否缩放的机制,以使得其子`Canvas`均能正确地进行缩放

2. `Toplevel`: 顶级窗口类

    继承于`tkinter.Toplevel`和`Tk`,加入了对`tkintertools`模块中的`Canvas`对象的支持,其余均与`Tk`一样

3. `Canvas`: 画布类

    继承于`tkinter.Canvas`,加入了对画布虚拟控件的支持,同时是各类响应事件、缩放控制的管理者,也对`tkinter.Canvas`的实例方法有一定的兼容性

### Virtual Canvas Widget/虚拟画布控件

1. `Label`: 标签控件

    标签控件的功能和`tkinter.Label`的功能类似,但更加的多元化  
    下面是`Label`控件的外观:  

    ![LabelTest.png](readme_res/LabelTest.png)

    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('LabelTest', 1000, 400)
    canvas = tkt.Canvas(root, 1000, 400, 0, 0)


    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(510, 175, 480, 150)
    tkt.Label(canvas, 50, 50, 400, 100, text='NormalLabel\nHere is the text')
    tkt.Label(canvas, 50, 200, 400, 100, radius=20, text='RoundCornerLabel')
    tkt.Label(canvas, 550, 50, 400, 100, text='DisableLabel').set_live(False)
    tkt.Label(canvas, 550, 200, 400, 100, radius=20,
            text='TransparentLabel', color_fill=tkt.COLOR_NONE)

    root.mainloop()
    ```

    </details>

2. `Button`: 按钮控件

    按钮控件相较于`tkinter.Button`,其自由度更高,`tkinter.Button`只有在按下的时候才能触发绑定的关联事件,而`Button`却可以在鼠标移至按钮上方时、鼠标按下时、鼠标松开时都可以绑定关联事件  
    下面是`Button`控件的外观:

    ![ButtonTest.png](readme_res/ButtonTest.png)

    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('ButtonTest', 500, 500)
    canvas = tkt.Canvas(root, 500, 500, 0, 0)


    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(50, 280, 400, 100)
    tkt.Button(canvas, 150, 135, 200, 50, text='NormalButton')
    tkt.Button(canvas, 100, 195, 300, 50, radius=10, text='RoundCornerButton')
    tkt.Button(canvas, 150, 255, 200, 50, text='DisableButton').set_live(False)
    tkt.Button(canvas, 100, 315, 300, 50, radius=10,
            text='TransparentButton', color_fill=tkt.COLOR_NONE)

    root.mainloop()
    ```

    </details>

3. `CheckButton`: 复选框控件

    复选框控件相对于`tkinter`原生的`tkinter.CheckButton`在使用方面更加地简单,同时颜值也上升了不少  
    下面是`CheckButton`控件的外观:

    ![CheckButtonTest.png](readme_res/CheckButtonTest.png)

    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('CheckButtonTest', 500, 300)
    canvas = tkt.Canvas(root, 500, 300, 0, 0)


    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(40, 190, 420, 50)
    tkt.CheckButton(canvas, 50, 50, 30, text='NormalCheckButton', value=True)
    tkt.CheckButton(canvas, 50, 100, 30, text='DisableCheckButton',
                    value=True).set_live(False)
    tkt.CheckButton(canvas, 50, 150, 30, radius=10, text='RoundCornerCheckButton')
    tkt.CheckButton(canvas, 50, 200, 30, radius=15,
                    text='TransparentCheckButton', color_fill=tkt.COLOR_NONE)

    root.mainloop()
    ```

    </details>

4. `Entry`: 输入框控件

    输入框控件可以轻松地设置输入的文本位置(靠左、居中和靠右),同时,它可以在鼠标移至输入框上方、鼠标未在输入框上方两种状态显示不同的默认文本  
    下面是`Entry`控件的外观:

    ![EntryTest.png](readme_res/EntryTest.png)
    
    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('EntryTest', 500, 400)
    canvas = tkt.Canvas(root, 500, 400, 0, 0)


    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(50, 193, 400, 100)
    tkt.Entry(canvas, 20, 20, 200, 30, text=('LeftEntry', 'Enter'))
    tkt.Entry(canvas, 20, 55, 200, 30, text=(
        'CenterEntry', 'Enter'), justify='center')
    tkt.Entry(canvas, 20, 90, 200, 30, text=(
        'RightEntry', 'Enter'), justify='right')
    tkt.Entry(canvas, 270, 20, 200, 30, radius=8, text='LeftEntry')
    tkt.Entry(canvas, 270, 55, 200, 30, radius=8,
            text='CenterEntry', justify='center')
    tkt.Entry(canvas, 270, 90, 200, 30, radius=8,
            text='RightEntry', justify='right')
    tkt.Entry(canvas, 100, 150, 300, 35, text=('PasswordEntry',
            'Click To Enter'), justify='center', show='●')
    tkt.Entry(canvas, 100, 200, 300, 35, text='DisableEntry',
            justify='center').set_live(False)
    tkt.Entry(canvas, 100, 250, 300, 35, text='TransparentEntry',
            justify='center', color_fill=tkt.COLOR_NONE)

    root.mainloop()
    ```

    </details>

5. `Text`: 文本框控件

    文本框类似于输入框,这里就不再赘述  
    下面是`Text`控件的外观:

    ![TextTest.png](readme_res/TextTest.png)
    
    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('TextTest', 1000, 400)
    canvas = tkt.Canvas(root, 1000, 400, 0, 0)


    def colorful(x, y, width, height) -> None:  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(510, 175, 480, 150)
    tkt.Text(canvas, 50, 50, 400, 100, text=('NormalText(Left)', 'Click To Enter'))
    tkt.Text(canvas, 50, 200, 400, 100, radius=20,
            text='RoundCornerText(Center)', justify='center')
    tkt.Text(canvas, 550, 50, 400, 100, text='DisableText').set_live(False)
    tkt.Text(canvas, 550, 200, 400, 100, radius=20,
            text='TransparentText(Right)', justify='right', color_fill=tkt.COLOR_NONE)

    root.mainloop()
    ```

    </details>

6. `Progressbar`: 进度条控件

    进度条控件相比`tkinter.ttk.Progressbar`,外观上的自由度较大  
    下面是`Progressbar`控件的外观:

    ![ProgressbarTest.png](readme_res/ProgressbarTest.png)

    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('ProgressbarTest', 500, 500)
    canvas = tkt.Canvas(root, 500, 500, 0, 0)


    def colorful(x, y, width, height) -> None:  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#0000FF'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)


    colorful(30, 290, 440, 50)
    tkt.Progressbar(canvas, 50, 50, 400, 30)
    tkt.Progressbar(canvas, 50, 100, 400, 30).load(.6667)
    tkt.Progressbar(canvas, 50, 150, 400, 30, borderwidth=5).load(1)
    (_ := tkt.Progressbar(canvas, 50, 200, 400, 30)).load(0.3333)
    _.set_live(False)
    tkt.Progressbar(canvas, 50, 250, 400, 30, color_bar=(
        'lightyellow', 'skyblue')).load(.5)
    tkt.Progressbar(canvas, 50, 300, 400, 30, color_bar=('', 'orange')).load(.1667)

    progressbar = tkt.Progressbar(canvas, 50, 375, 400, 30)
    progressbar_2 = tkt.Progressbar(canvas, 50, 425, 400, 30)


    def load(total, count=0):  # type: (int, int) -> None
        """ load progressbar """
        progressbar.load(count/total)
        progressbar_2.load(1-count/total)
        if count < total:
            root.after(3, load, total, count+1)


    load(10000)
    root.mainloop()
    ```

    </details>

### Tool Class/工具类

1. `PhotoImage`: 图片类

    `PhotoImage`类继承于`tkinter.PhotoImage`,它是在`tkinter.PhotoImage`的基础上做功能的强化,对 gif 动图有很好的支持,仅需极少量代码即可实现动图的显示,还可以设置动图显示的速度,此外,对 png 类型的图片的支持也有强化,可以在不依赖任何第三方模块或者库的情况下,对 png 图片进行缩放

2. `Singleton`: 单例模式类

    单例模式,不用介绍了吧?通过继承它来使用

### Tool Function/工具函数

1. `move`: <a name="move">移动函数</a>

    移动函数可以轻松地按一定的规律、移动速度、移动时间去移动`tkintertools`模块内的所有对象,同时兼容了`tkinter`内的对象,即`tkinter`中的对象也可以很方便地移动,甚至它还可以移动窗口的位置!

    ![MoveTest.gif](readme_res/MoveTest.gif)
    
    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('MoveTest', 500, 500)
    canvas = tkt.Canvas(root, 500, 500, 0, 0)
    rect = canvas.create_rectangle(50, 350, 150, 450)


    def move_window(switch=[True]):  # type: (list[bool]) -> None
        tkt.move(root, None, 1000 if switch[0] else -1000, 0, 800, mode='flat')
        switch[0] = not switch[0]


    def move_button(switch=[True]) -> None:  # type: (list[bool]) -> None
        tkt.move(canvas, button, 200 if switch[0]
                else -200, 0, 500, mode='rebound')
        switch[0] = not switch[0]


    def move_rect(switch=[True]):  # type: (list[bool]) -> None
        tkt.move(canvas, rect, 200 if switch[0] else -200, 0, 500, mode='smooth')
        switch[0] = not switch[0]


    tkt.Button(canvas, 50, 50, 200, 40, radius=10,
            text='MoveWindow', command=move_window)
    tkt.Button(canvas, 50, 100, 200, 40, radius=10,
            text='MoveRect', command=move_rect)
    button = tkt.Button(canvas, 50, 150, 200, 40, radius=10,
                        text='MoveButton', command=move_button)

    root.mainloop()
    ```

    </details>

2. `text`: 文本函数

    可以快速并方便地得到一个参数长度的字符串,且字符串的内容可以指定位置  
    如:得到一个 20 长度的字符串 “tkintertools”  
    <pre>
    `left`   : "tkintertools        "  
    `center` : "    tkintertools    "  
    `right`  : "        tkintertools"</pre>

3. `color`: <a name="Gradient">颜色函数</a>

    颜色函数可以轻松求出一个颜色到另外一个颜色的过渡颜色,因此可以轻松得到渐变色的效果,同时,改变传入的参数还可以得到传入颜色的对比色  
    第二张图是 test.py 在图像测试中绘制的图案

    ![ColorTest.png](readme_res/ColorTest.png)

    ![Test_Draw.png](readme_res/Test_Draw.png)

    <details><summary><b>源代码</b></summary>

    ```python
    import tkintertools as tkt

    root = tkt.Tk('ColorTest', 500, 500)
    canvas = tkt.Canvas(root, 500, 500, 0, 0)


    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None
        """ Gradient colors """
        for i in range(width):
            color = tkt.color(('#FF0000', '#00FF00'), i/width)
            color_2 = tkt.color(('#FFFFFF', '#000000'), i/width)
            canvas.create_line(x+i, y, x+i, y+height, fill=color)
            canvas.create_oval(250-i/3, 300-i/3, 250+i/3, 300 +
                            i/3, outline=color_2, width=2)


    colorful(50, 50, 400, 100)
    root.mainloop()
    ```

    </details>

4. `askfont`: 字体选择对话框

    `askfont`函数可以打开默认的字体选择窗口,这个窗口虽然是默认的,但它实际上无法在`tkinter`中打开,因为`tkinter`并没有对应的 API 能够做到这一点。但是,`tkintertools`调用并封装了原生的 tcl 的命令,使得字体选择框能够被我们使用。

    ![font.png](readme_res/font.png)

5. `SetProcessDpiAwareness`: <a name="DPI">DPI 级别设置函数</a>

    这个函数实际上只是对函数`ctypes.WinDLL('shcore').SetProcessDpiAwareness`的一个简单包装,其值可为 0、1 和 2,分别代表程序 DPI 的不同级别,那么缩放效果也就不同,`tkintertools`选择的值是 1,但程序默认值实际为 0  
    下面是未执行这个函数的效果
    
    ![SetProcessDpiAwareness_0.png](readme_res/SetProcessDpiAwareness_0.png)

    <p>下面是执行了这个函数的效果</p>

    ![SetProcessDpiAwareness_1.png](readme_res/SetProcessDpiAwareness_1.png)

    从上面的两张图中可以很明显的看出第一张很模糊,第二张很清晰,这就是 DPI 级别不同的原因,不过这一点在屏幕缩放比不是 100% 的时候才会出现  
    大家对上面的图肯定很熟悉,这不就是 IDLE 吗!?对,这个的问题的解决办法也是来自于 IDLE 的源代码 [pyshell.py line 18~20]  
    注意:该函数在程序的不同位置执行的效果不一样!一般用在`mainloop`之前,但`tkintertools`已经在`mainloop`函数中嵌入了该函数,无需再设置一次 DPI 级别,此函数是为了原生`tkinter`程序用的。

Examples/实战示例
----------------

以下三个为使用了 tkintertools 的典型案例,供大家参考,程序均免费,源代码开放!  
前面两个是我一边改进 tkintertools 模块,一边写的实战,有一定的 bug,但不影响正常使用。  
只有把模块真正地用到实战上去,才知道哪有 bug,哪里还需要改进!

### 任务清单小工具

* 文章链接: https://xiaokang2022.blog.csdn.net/article/details/128561339
* 代码仓库: https://gitcode.net/weixin_62651706/todolist
* 程序下载(含打包好的程序和源代码): https://wwc.lanzoum.com/iyxL30kpkcbe
* 推荐指数: 👍

这个案例使用了 tkintertools-v2.5.7 版本(新版已无法兼容),含有一些 bug,大量采用了 tkintertools 的控件,取得了比较好的界面效果。体现了 tkintertools 模块与 tkinter 模块相比在颜值上的碾压性!

![todolist.gif](https://img-blog.csdnimg.cn/img_convert/dc1a598c3f082253c1ebc7bbca0b98ce.gif)

![todolist.gif](https://img-blog.csdnimg.cn/img_convert/7f34451deda1af13712a9edcb37f20b4.gif)

### 中国象棋游戏

* 文章链接: https://xiaokang2022.blog.csdn.net/article/details/128852029
* 代码仓库: https://gitcode.net/weixin_62651706/chess
* 程序下载(含打包好的程序和源代码): https://wwc.lanzoum.com/iwgp00mlewpa
* 推荐指数: 👍👍

注意:源代码有解压密码,解压密码在链接文章中,请仔细查找!  
这个案例使用了 tkintertools-v2.5.9.5 版本(新版已无法兼容), 含有少量 bug,部分 UI 采用了 tkintertools,部分 UI 采用了 tkinter,属于混合使用。体现了 tkintertools 模块对 tkinter 模块的兼容性!

![chess.png](https://img-blog.csdnimg.cn/43df0568d4b34078a443a098b67c126a.png)

![chess.png](https://img-blog.csdnimg.cn/fc768093715d47d7b14bea015a921e3d.png)

### 简易登录界面

* 文章链接: 暂无
* 代码仓库: https://gitcode.net/weixin_62651706/tester
* 程序下载: 暂无
* 推荐指数: 👍👍👍

这个案例使用了最新稳定版的 tkintertools-v2.6.0,界面非常稳定,几乎没有 bug,完全采用 tkintertools 的控件,颜值很高,界面非常流畅。体现了 tkintertools 模块与 tkinter 模块相比在性能上的优越性!

![exam3_1.png](readme_res/exam3_1.png)

![exam3_2.png](readme_res/exam3_2.png)

More/更多
---------

> GitHub:  
> https://github.com/Xiaokang2022/tkintertools

> Gitee(Mirror/镜像):  
> https://gitee.com/xiaokang-2022/tkintertools

> GitCode(Mirror/镜像):  
> https://gitcode.net/weixin_62651706/tkintertools

还有更多内容请在 [源代码](tkintertools/) 中探索!

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Xiaokang2022/tkintertools",
    "name": "tkintertools-dev",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "tkinter,tkintertools,GUI",
    "author": "Xiaokang2022",
    "author_email": "2951256653@qq.com",
    "download_url": "https://files.pythonhosted.org/packages/24/ab/736e49cdca517e7e93645ae1e599d232e2872a3230456ee804cd31272cc0/tkintertools-dev-2.6.5.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\r\n    <h1>\ud83d\ude80tkintertools\ud83d\ude80</h1>\r\n    <p><img height=\"128px\" alt=\"logo.png\" src=\"tkt.png\" /></p>\r\n    <p>\r\n    The <code>tkintertools</code> module is an auxiliary module of the <code>tkinter</code> module\r\n    <br />\r\n    <code>tkintertools</code> \u6a21\u5757\u662f <code>tkinter</code> \u6a21\u5757\u7684\u8f85\u52a9\u6a21\u5757\r\n    </p>\r\n    <p>\r\n        <a href=\"tkintertools/__init__.py\">\r\n            <img src=\"https://img.shields.io/badge/Version-2.6.5(dev)-blue\" alt=\"latest version\" />\r\n        </a>\r\n        <a href=\"LICENSE\">\r\n            <img src=\"https://img.shields.io/badge/License-Mulan PSL v2-green\" alt=\"License\" />\r\n        </a>\r\n        <a href=\"CHANGELOG.md\">\r\n            <img src=\"https://img.shields.io/badge/ChangeLog-2023/06/13-orange\" alt=\"ChangeLog\" />\r\n        </a>\r\n        <a href=\"TODO.md\">\r\n            <img src=\"https://img.shields.io/badge/ToDo-14-yellow?logo=cachet\" alt=\"ToDos\" />\r\n        </a>\r\n        <a href=\"https://pypistats.org/packages/tkintertools\">\r\n            <img src=\"https://img.shields.io/badge/Download-4k-purple?logo=pypi\" alt=\"Downloads\" />\r\n        </a>\r\n        <br />\r\n        <a href=\"mailto:2951256653@qq.com\">\r\n            <img src=\"https://img.shields.io/badge/Email-2951256653@qq.com-cyan\" alt=\"Email\" />\r\n        </a>\r\n        <a href=\"https://github.com/Xiaokang2022\">\r\n            <img src=\"https://img.shields.io/badge/Author-\u5c0f\u5eb72022-white\" alt=\"Author\" />\r\n        </a>\r\n        <a href=\"https://xiaokang2022.blog.csdn.net\">\r\n            <img src=\"https://img.shields.io/badge/Blog-\u5c0f\u5eb72022@CSDN-red\" alt=\"Blog\" />\r\n        </a>\r\n    </p>\r\n</div>\r\n\r\nInstall/\u6a21\u5757\u5b89\u88c5\r\n---------------\r\n\r\n### Stable version/\u7a33\u5b9a\u7248\u672c\r\n\r\n* Version/\u7248\u672c : 2.6.4\r\n* Release Date/\u53d1\u5e03\u65e5\u671f : 2023/06/12\r\n\r\n\u8fd9\u4e2a\u662f\u76ee\u524d\u7684\u6700\u65b0\u7a33\u5b9a\u7248\uff0c\u6bd4\u8f83\u7a33\u5b9a\uff0cbug \uff08\u53ef\u80fd\uff09\u6ca1\u6709\u90a3\u4e48\u591a\uff0c\u63a8\u8350\u4f7f\u7528\u8fd9\u4e2a\u3002  \r\n\u5173\u4e8e\u7a33\u5b9a\u7248\u6709 Issue \u7684\u8bdd\uff0c\u6211\u4f1a\u53bb\u67e5\u770b\u5e76\u5c1d\u8bd5\u89e3\u51b3 Issue\u3002\r\n\r\n```\r\npip install tkintertools==2.6.4\r\n```\r\n\r\n### Development version/\u5f00\u53d1\u7248\u672c\r\n\r\n* Version/\u7248\u672c : 2.6.5\r\n* Release Date/\u53d1\u5e03\u65e5\u671f : 2023/06/13\r\n\r\n\u8fd9\u4e2a\u662f\u6211\u6b63\u5728\u5f00\u53d1\u7684\u7248\u672c\uff0c\u53ef\u80fd\u6709\u65b0\u529f\u80fd\uff0cbug \u4e5f\u53ef\u80fd\u4f1a\u6bd4\u8f83\u591a\uff0c\u4f46\u4e5f\u53ef\u80fd\u4f1a\u6bd4\u539f\u6765\u7684\u7248\u672c\u66f4\u52a0\u7a33\u5b9a\u3002  \r\n\u5927\u5bb6\u53ef\u4ee5\u5728 Issue \u4e2d\u63d0\u51fa\u4e00\u4e9b\u5efa\u8bae\uff0c\u6211\u4f1a\u9002\u5f53\u91c7\u7eb3\u4e00\u4e9b\u5e76\u5728\u5f00\u53d1\u7248\u672c\u4e2d\u66f4\u6539\u6216\u5b9e\u73b0\u3002\r\n\r\n```\r\npip install tkintertools-dev==2.6.5\r\n```\r\n\r\n**Attention/\u7279\u522b\u6ce8\u610f**\r\n* \u5f00\u53d1\u7248\u4ec5\u4f5c\u793a\u4f8b\uff0c\u5404\u51fd\u6570\u6216\u7c7b\u7684API\u5e76\u975e\u6700\u7ec8\u786e\u5b9a\u7ed3\u679c\uff0c\u76f4\u63a5\u4f7f\u7528\u5f00\u53d1\u7248\u53ef\u80fd\u5bfc\u81f4\u540e\u7eed\u65e0\u6cd5\u4e0e\u6b63\u5f0f\u7248\u517c\u5bb9\uff01\r\n* \u82e5\u8981\u4f7f\u7528\u5f00\u53d1\u7248\uff0c\u8bf7\u5148\u5378\u8f7d\u6b63\u5f0f\u7248\u540e\u518d\u8fdb\u884cpip\u5b89\u88c5\uff0c\u518d\u6b21\u4f7f\u7528\u6b63\u5f0f\u7248\u65f6\u4e5f\u662f\u4e00\u6837\uff0c\u5148\u5378\u8f7d\u5f00\u53d1\u7248\u518d\u5b89\u88c5\u6b63\u5f0f\u7248\uff01\r\n\r\n### Environmental requirements/\u73af\u5883\u9700\u6c42\r\n\r\n\u6ca1\u6709\u4efb\u4f55\u989d\u5916\u7684\u4f9d\u8d56\u5305\uff08\u9664\u4e86tkinter\uff09\uff0c\u4f46\u53ea\u652f\u6301\u4ee5\u4e0b Python \u7248\u672c:\r\n\r\n![Python3.8](https://img.shields.io/badge/Python-3.8.*-blue?logo=python)\r\n![Python3.9](https://img.shields.io/badge/Python-3.9.*-blue?logo=python)\r\n![Python3.10](https://img.shields.io/badge/Python-3.10.*-blue?logo=python)\r\n![Python3.11](https://img.shields.io/badge/Python-3.11.*-blue?logo=python)\r\n![Python3.12](https://img.shields.io/badge/Python-3.12.*-blue?logo=python)\r\n\r\n\u53ef\u80fd\u5728\u67d0\u4e9b\u64cd\u4f5c\u7cfb\u7edf\u4e0a\u4e5f\u53ef\u8fd0\u884c\uff0c\u4f46\u76ee\u524d\u4ee5\u4e0b\u64cd\u4f5c\u7cfb\u7edf\u5df2\u7ecf\u6d4b\u8bd5\u901a\u8fc7:\r\n\r\n![Windows10](https://img.shields.io/badge/Windows-10-green?logo=windows)\r\n![Windows11](https://img.shields.io/badge/Windows-11-green?logo=windows11)\r\n![Ubuntu22.04](https://img.shields.io/badge/Ubuntu-22.04-green?logo=ubuntu)\r\n\r\n<a name=\"news\">News/\u6700\u65b0\u529f\u80fd</a>\r\n------------\r\n\r\n\u6700\u65b0\u5f00\u53d1\u7248\uff082.6.5-dev\uff09\u65b0\u5185\u5bb9:\r\n\r\n- [X] \u5b50\u6a21\u5757`tools_3d`\u65b0\u589e\u7c7b`Space`\u53ef\u4ee5\u76f4\u63a5\u63d0\u4f9b\u5bf93D\u5bf9\u8c61\u8fdb\u884c\u5e73\u79fb\u3001\u65cb\u8f6c\u548c\u7f29\u653e\u7b49\u64cd\u4f5c\u7684\u529f\u80fd\r\n- [X] \u4fee\u590d\u4e86\u7c7b`Cuboid`\u548c\u7c7b`Tetrahedron`\u6ca1\u6709\u5c06\u5b9e\u4f8b\u6dfb\u52a0\u5230\u7236\u7c7b`Canvas_3D`\u7684bug\r\n- [X] \u4fee\u590d\u4e86\u5f533D\u5bf9\u8c61\u51fa\u73b0\u5728\u76f8\u673a\u4f4d\u7f6e\u540e\u9762\u65f6\u4f1a\u663e\u793a\u9519\u8bef\u7684bug\r\n- [X] \u4fee\u590d\u4e86\u90e8\u5206\u9519\u8bef\u7684\u7c7b\u578b\u63d0\u793a\r\n\r\n\u6700\u65b0\u7a33\u5b9a\u7248\uff082.6.4\uff09\u65b0\u5185\u5bb9:\r\n\r\n\u65b0\u589e\u4e86\u5bf93d\u51e0\u4f55\u4f53\u7a7a\u95f4\u4f4d\u7f6e\u6392\u5e8f\u7684\u652f\u6301\uff0c\u4f7f\u5f97\u51e0\u4f55\u4f53\u4e0d\u518d\u53ea\u6709\u7c97\u7565\u7684\u7ebf\u6761\uff0c\u800c\u62e5\u6709\u4e30\u5bcc\u7684\u989c\u8272\u3002\r\n\r\n\u5728 Windows \u7cfb\u7edf\u4e0b\u8fd0\u884c\u4e0b\u9762\u7684\u793a\u4f8b\u7a0b\u5e8f\u65f6\uff0c\u5176\u62e5\u6709\u4ee5\u4e0b\u529f\u80fd\uff1a\r\n* \u6309\u4f4f\u9f20\u6807\u5de6\u952e\u62d6\u52a8\u53ef\u4ee5\u65cb\u8f6c\u8fd9\u591a\u4e2a\u51e0\u4f55\u4f53\uff1b\r\n* \u6309\u4f4f\u9f20\u6807\u53f3\u952e\u62d6\u52a8\u53ef\u4ee5\u79fb\u52a8\u8fd9\u4e9b\u51e0\u4f55\u4f53\u5728\u7a7a\u95f4\u4e2d\u7684\u4f4d\u7f6e\uff1b\r\n* \u6309\u201c=\u201d\u548c\u201c-\u201d\u952e\u5206\u522b\u53ef\u4ee5\u653e\u5927\u548c\u7f29\u5c0f\u51e0\u4f55\u4f53\u7684\u5927\u5c0f\uff1b\r\n* \u6eda\u52a8\u9f20\u6807\u4e2d\u952e\u53ef\u4ee5\u653e\u5927\u548c\u7f29\u5c0f\u753b\u9762\u3002\r\n\r\n\u4e0b\u9762\u662f\u793a\u4f8b\u7a0b\u5e8f\u7684\u6548\u679c\u56fe\uff1a\r\n\r\n![news.png](news.png)\r\n\r\n<details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n```python\r\nfrom tkinter import Event\r\n\r\nimport tkintertools as tkt\r\nfrom tkintertools import tools_3d as t3d\r\n\r\nroot = tkt.Tk('tool_3d', 1280, 720)\r\ncv3d = t3d.Canvas_3D(root, 1280, 720, 0, 0)\r\n\r\norigin = t3d.Point(cv3d, [0, 0, 0])  # \u539f\u70b9\r\nk = -100, 0, 100\r\ngeos = [t3d.Cuboid(cv3d, a-50, b-50, c-50, 100, 100, 100, color_up='white', color_down='yellow', color_left='red',\r\n                   color_right='orange', color_front='blue', color_back='green') for a in k for b in k for c in k]\r\ncv3d.space_sort()\r\n\r\n\r\ndef translate(event, flag=False, _cache=[]):\r\n    # type: (Event, bool, list[float]) -> None\r\n    \"\"\" \u5e73\u79fb\u4e8b\u4ef6 \"\"\"\r\n    if flag:\r\n        _cache[:] = [event.x, event.y]\r\n        return\r\n    dx = (event.x - _cache[0])\r\n    dy = (event.y - _cache[1])\r\n    _cache[:] = [event.x, event.y]\r\n    for geo in geos:\r\n        geo.translate(0, dx, dy)\r\n        geo.update()\r\n    origin.translate(0, dx, dy)\r\n    origin.update()\r\n    cv3d.space_sort()\r\n\r\n\r\ndef rotate(event, flag=False, _cache=[]):\r\n    # type: (Event, bool, list[float]) -> None\r\n    \"\"\" \u65cb\u8f6c\u4e8b\u4ef6 \"\"\"\r\n    if flag:\r\n        _cache[:] = [event.x, event.y]\r\n        return\r\n    dy = (event.x - _cache[0]) / 100\r\n    dx = (_cache[1] - event.y) / 100\r\n    _cache[:] = [event.x, event.y]\r\n    for item in geos:\r\n        item.rotate(0, dx, dy, center=origin.coords)\r\n        item.update()\r\n    cv3d.space_sort()\r\n\r\n\r\ndef scale(event):  # type: (Event) -> None\r\n    \"\"\" \u7f29\u653e\u4e8b\u4ef6 \"\"\"\r\n    k = 1.05 if event.keysym == 'equal' else 0.95 if event.keysym == 'minus' else 1\r\n    for geo in geos:\r\n        geo.scale(k, k, k)\r\n        geo.update()\r\n    cv3d.space_sort()\r\n\r\n\r\ndef scale_center(event):  # type: (Event) -> None\r\n    \"\"\" \u4e2d\u5fc3\u7f29\u653e\u4e8b\u4ef6 \"\"\"\r\n    k = 1.05 if event.delta > 0 else 0.95\r\n    for geo in geos:\r\n        geo.scale(k, k, k, center=origin.coords)\r\n        geo.update()\r\n    cv3d.space_sort()\r\n\r\n\r\nroot.bind('<Button-1>', lambda event: rotate(event, True))\r\nroot.bind('<B1-Motion>', rotate)\r\nroot.bind('<Button-3>', lambda event: translate(event, True))\r\nroot.bind('<B3-Motion>', translate)\r\nroot.bind('<Any-Key>', scale)\r\nroot.bind('<MouseWheel>', scale_center)\r\nroot.mainloop()\r\n```\r\n\r\n</details>\r\n\r\n\u66f4\u591a\u66f4\u65b0\u4fe1\u606f\u8bf7\u89c1\uff1a[CHANGELOG.md](CHANGELOG.md)\r\n\r\nDescription/\u6a21\u5757\u8bf4\u660e\r\n----------------------\r\n\r\ntkintertools \u662f\u4e00\u6b3e\u57fa\u4e8e tkinter \u6a21\u5757\u7684\u4e8c\u6b21\u5f00\u53d1\u7684\u754c\u9762\u7f16\u7a0b\u6a21\u5757\uff0c\u5b83\u5b8c\u5168\u6ca1\u6709\u4f7f\u7528\u4efb\u4f55\u7b2c\u4e09\u65b9\u6a21\u5757\u548c\u5e93\u7684\uff0c\u540c\u65f6\uff0c\u5b83\u4e5f\u6ca1\u6709\u4efb\u4f55\u4f9d\u8d56\u5305\uff0c\u5b83\u7684\u529f\u80fd\u5b8c\u5168\u7531\u5185\u7f6e\u6a21\u5757\u548c\u51fd\u6570\u5b9e\u73b0\uff0c\u800c\u4e14\uff0c\u5b83\u8fd8\u662f\u8de8\u5e73\u53f0\u7684\uff01\u5b83\u548c tkinter \u6700\u5927\u7684\u4e0d\u540c\u5728\u4e8e\uff0c\u5b83\u7684\u63a7\u4ef6\u5e76\u975e\u771f\u5b9e\u7684\u63a7\u4ef6\uff0c\u800c\u662f\u5728 tkinter \u6a21\u5757\u4e2d Canvas \u5bf9\u8c61\u4e2d\u7ed8\u5236\u800c\u6210\u7684\uff0c\u8fd9\u5c31\u8d4b\u4e88\u4e86 tkintertools \u63a7\u4ef6\u4e00\u4e9b\u5728 tkinter \u4e2d\u6ca1\u6709\u7684\u7279\u6027\uff0c\u5217\u4e3e\u5982\u4e0b\uff1a\r\n\r\n* \u63a7\u4ef6\u80cc\u666f\u53ef\u4ee5\u662f\u900f\u660e\u7684\uff08\u5b9e\u9645\u4e0a\u662f\u6ca1\u6709\u80cc\u666f\u989c\u8272\uff09\r\n* \u63a7\u4ef6\u7684\u6837\u5f0f\u53ef\u4ee5\u662f\u81ea\u5b9a\u4e49\u7684\uff08\u6bd4\u5982\u6309\u94ae\u6709\u5706\u89d2\uff09\r\n* \u63a7\u4ef6\u7684\u521b\u5efa\u901f\u5ea6\u8fdc\u5927\u4e8e tkinter \u7684\u63a7\u4ef6\uff08\u9664\u4e86 Canvas \u63a7\u4ef6\uff09\r\n\r\n\u4f46\u540c\u65f6\u4e5f\u4ea7\u751f\u4e86\u4e00\u4e9b\u7f3a\u70b9\uff1a\r\n\r\n* \u865a\u62df\u7684\u63a7\u4ef6\u65e0\u6cd5\u83b7\u53d6\u7126\u70b9\r\n* \u865a\u62df\u7684\u63a7\u4ef6\u5728\u6587\u672c\u8f93\u5165\u548c\u663e\u793a\u7684\u529f\u80fd\u4e0a\u5b58\u5728\u4e00\u4e9b\u7f3a\u9677\uff08\u8fd9\u4e2a\u7f3a\u9677\u4e0d\u662f\u5f88\u660e\u663e\uff0c\u4f46\u5f3a\u8feb\u75c7\u5c31\u6709\u70b9\u96be\u53d7\u4e86\uff0c\u6bd4\u5982\u6211\uff09\r\n\r\ntkintertools \u6a21\u5757\u8fd8\u5177\u6709\u4e00\u4e9b\u7279\u8272\u7684\u529f\u80fd\uff1a\r\n\r\n* \u5229\u7528 tkinter \u548c tkintertools \u521b\u5efa\u7684\u7a0b\u5e8f\uff0c\u5728\u9ad8\u5206\u8fa8\u7387\u7684\u60c5\u51b5\u4e0b\uff0ctkintertools \u7684\u4f1a\u66f4\u52a0\u6e05\u6670\uff08\u8fd9\u70b9\u5bf9\u4e8e\u7b14\u8bb0\u672c\u7528\u6237\u5f88\u53cb\u597d\uff0c\u6bd4\u5982\u6211\uff09\r\n* \u53ef\u4ee5\u8fc5\u901f\u5b9e\u73b0\u6e10\u53d8\u8272\u7684\u6548\u679c\r\n* \u7a97\u53e3\u7f29\u653e\uff0c\u6240\u6709\u7684\u63a7\u4ef6\u7684\u5927\u5c0f\u8ddf\u7740\u7f29\u653e\uff08\u5f53\u7136\uff0c\u4e5f\u53ef\u4ee5\u8bbe\u7f6e\u4e3a\u4e0d\u8ddf\u968f\u7f29\u653e\uff09\r\n* \u5b50\u6a21\u5757 tools_3d \u53ef\u4ee5\u662f\u6ee1\u8db3\u7b80\u5355\u7684 3D \u7ed8\u56fe\u9700\u6c42\r\n\r\nProvides/\u6a21\u5757\u529f\u80fd\r\n-------------------\r\n\r\nHere, only the more distinctive features will be listed  \r\n\u8fd9\u91cc\u53ea\u4f1a\u5217\u4e3e\u51fa\u6bd4\u8f83\u5177\u6709\u7279\u8272\u7684\u529f\u80fd\r\n\r\n### Customizable widgets/\u53ef\u81ea\u5b9a\u4e49\u7684\u63a7\u4ef6\r\n\r\ntkintertools \u6a21\u5757\u7684\u63a7\u4ef6\u62e5\u6709\u8bb8\u591a\u53c2\u6570\u4f9b\u6211\u4eec\u8bbe\u7f6e\uff0c\u6bd4\u5982\u5706\u89d2\u7684\u534a\u5f84\u3001\u6587\u672c\u548c\u8fb9\u6846\u4ee5\u53ca\u63a7\u4ef6\u5185\u90e8\u7684\u989c\u8272\uff0c\u5173\u8054\u4e8b\u4ef6\u7b49\u7b49\u3002  \r\n\u8fd9\u91cc\u8981\u8bf4\u660e\u7684\u662f\uff0c\u6bcf\u4e2a\u63a7\u4ef6\u53ef\u4ee5\u8bbe\u7f6e\u7684\u5173\u8054\u4e8b\u4ef6\u4e0d\u6b62\u4e00\u79cd\uff0c\u5728\u9f20\u6807\u7ecf\u8fc7\u63a7\u4ef6\u65f6\u53ef\u4ee5\u7ed1\u5b9a\u4e8b\u4ef6\uff0c\u9f20\u6807\u70b9\u51fb\u63a7\u4ef6\u4e5f\u53ef\u4ee5\uff0c\u9f20\u6807\u70b9\u51fb\u540e\u677e\u5f00\u4e5f\u884c\u7b49\u7b49\u3002  \r\n\u6587\u672c\u548c\u8fb9\u6846\u4ee5\u53ca\u63a7\u4ef6\u7684\u586b\u5145\u8272\u4e5f\u662f\u7c7b\u4f3c\u7684\uff0c\u5728\u9f20\u6807\u7ecf\u8fc7\u63a7\u4ef6\u3001\u70b9\u51fb\u63a7\u4ef6\u3001\u70b9\u51fb\u540e\u677e\u5f00\u90fd\u53ef\u4ee5\u8bbe\u5b9a\u989c\u8272\u3002  \r\n\u6587\u672c\u7c7b\u63a7\u4ef6\u8fd8\u80fd\u591f\u4ece\u53f3\u8fb9\u9010\u6b65\u8f93\u5165\u6587\u672c\uff0c\u6587\u672c\u8f93\u5165\u63d0\u793a\u7b26\u4e5f\u53ef\u4ee5\u4e0d\u662f\u5355\u8c03\u65e0\u8da3\u7684\u7ad6\u7ebf\uff0c\u53ef\u4ee5\u662f\u5176\u4ed6\u7684\uff0c\u6bd4\u5982\u4e0b\u5212\u7ebf\u7b49\u3002  \r\n\u6700\u540e\uff0c\u5927\u5bb6\u53ef\u4ee5\u770b\u4e00\u4e0b [test.py](test.py) \u6587\u4ef6\u91cc\u9762\u7684\u793a\u4f8b\uff0c\u8fd9\u4e2a\u793a\u4f8b\u5c55\u793a\u4e86 tkintertools \u6a21\u5757\u7684\u7edd\u5927\u90e8\u5206\u529f\u80fd\uff0c\u793a\u4f8b\u4e2d\u66f4\u6709\u9690\u85cf\u7684 \u201c\u591a\u5f69\u53d8\u5e7b\u201d \u5f69\u86cb\u54e6\uff01\r\n\r\n### Automatically control size/\u81ea\u52a8\u63a7\u5236\u5927\u5c0f\r\n\r\ntkintertools \u4e2d\u7684\u63a7\u4ef6\uff0c\u5176\u5927\u5c0f\u548c\u5f62\u72b6\u53ef\u4ee5\u968f\u7740\u7a97\u53e3\u7684\u53d8\u5316\u800c\u6210\u6bd4\u4f8b\u5730\u53d8\u5316\uff0c\u4e0d\u4ec5\u4ec5\u662f\u63a7\u4ef6\u4e2d\u7684\u6587\u672c\uff0cCanvas \u7ed8\u5236\u7684\u56fe\u5f62\u4e5f\u4f1a\u968f\u4e4b\u53d8\u52a8\uff0c\u66f4\u8ba9\u4eba\u5174\u594b\u7684\u662f\uff0cpng \u7c7b\u578b\u7684\u56fe\u7247\u4e5f\u4f1a\u968f\u4e4b\u6210\u6bd4\u4f8b\u5730\u7f29\u653e\uff01\u5f53\u7136\uff0c\u4f60\u4e5f\u53ef\u4ee5\u8bbe\u5b9a\u53c2\u6570\u8ba9\u5176\u4e0d\u968f\u4e4b\u53d8\u52a8\uff0c\u4e5f\u53ef\u4ee5\u8bbe\u5b9a\u53c2\u6570\u4f7f\u5176\u5728\u7f29\u653e\u7684\u65f6\u5019\u4fdd\u6301\u6a2a\u7eb5\u65b9\u5411\u7684\u6bd4\u4f8b\u3002  \r\n\u603b\u4e4b\uff0c\u5f88\u65b9\u4fbf\uff0c\u5f88\u8212\u9002\uff01\r\n\r\n### Easily move widgets/\u8f7b\u677e\u79fb\u52a8\u63a7\u4ef6\r\n\r\n\u89c1 [\u79fb\u52a8\u51fd\u6570](#move)\r\n\r\n### Gradient colors/\u6e10\u53d8\u8272\r\n\r\n\u89c1 [\u989c\u8272\u51fd\u6570](#Gradient)\r\n\r\n### Automatically adapt to DPI/\u81ea\u52a8\u9002\u5e94DPI\r\n\r\n\u89c1 [DPI \u7ea7\u522b\u8bbe\u7f6e\u51fd\u6570](#DPI)\r\n\r\n### Detailed type hints/\u8be6\u7ec6\u7684\u7c7b\u578b\u63d0\u793a\r\n\r\n\u53c2\u8003 [PEP 526](https://peps.python.org/pep-0526/)\u3001[PEP 586](https://peps.python.org/pep-0586/)\u3001[PEP 604](https://peps.python.org/pep-0604/) \u548c [PEP 612](https://peps.python.org/pep-0612/)\uff0c\u6211\u91c7\u7528\u4e86\u6700\u517c\u5bb9\u7684\u65b9\u5f0f\u53bb\u5b9e\u73b0\u8be6\u7ec6\u7684\u7c7b\u578b\u63d0\u793a\uff0c\u53ef\u9002\u7528 IDE \u6709 VScode\u3001Pycharm \u7b49\u3002  \r\n\u90a3\u4ec0\u4e48\u662f\u7c7b\u578b\u63d0\u793a\u5462\uff1f\u8bdd\u4e0d\u591a\u8bf4\uff0c\u76f4\u63a5\u770b\u56fe\u5c31\u884c\uff1a\r\n\r\n![type_hint.png](readme_res/type_hint_vscode.png)\r\n\r\n\u5728 VSCode \u7f16\u8f91\u5668\u4e2d\uff0c\u5f53\u9f20\u6807\u79fb\u81f3\u7c7b\u6216\u8005\u51fd\u6570\u7684\u540d\u5b57\u4e0a\u9762\u65f6\uff0c\u4f1a\u81ea\u52a8\u663e\u793a\u8be5\u7c7b\u6216\u8005\u51fd\u6570\u7684\u6ce8\u91ca\u6587\u6863\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\uff0c\u4e0d\u9700\u8981\u770b\u592a\u591a\u7684\u5e2e\u52a9\u6587\u6863\u548c\u8d44\u6599\u5c31\u80fd\u719f\u7ec3\u5730\u4f7f\u7528 tkintertools \u6a21\u5757\uff01\r\n\r\n### Across Platforms/\u8de8\u5e73\u53f0\r\n\r\n[test.py](test.py) \u5728 Windows \u7cfb\u7edf\uff08**Windows10**\uff09\u4e0a\u8fd0\u884c\u7684\u754c\u9762\u5982\u4e0b\uff1a\r\n\r\n![test_windows10.png](readme_res/test_windows10.png)\r\n\r\n[test.py](test.py) \u5728 Linux \u7cfb\u7edf\uff08**Ubuntu22.04**\uff09\u4e0a\u8fd0\u884c\u7684\u754c\u9762\u5982\u4e0b\uff1a\r\n\r\n![test_linux.png](readme_res/test_linux.png)\r\n\r\n[test.py](test.py) \u5728 Windows \u7cfb\u7edf\uff08**Windows11**\uff09\u4e0a\u8fd0\u884c\u7684\u754c\u9762\u5982\u4e0b(\u667a\u80fd\u63a7\u5236\u5706\u89d2\u534a\u5f84)\uff1a\r\n\r\n![test_windows11.png](readme_res/test_windows11.png)\r\n\r\n### 3D Drawing/3D\u7ed8\u56fe\r\n\r\n\u89c1 [News/\u6700\u65b0\u529f\u80fd](#news)\r\n\r\nContents/\u6a21\u5757\u5185\u5bb9\r\n-------------------\r\n\r\nEach non internal class and function in the module will be described in detail here  \r\n\u8fd9\u91cc\u4f1a\u8be6\u7ec6\u8bf4\u660e\u6a21\u5757\u4e2d\u7684\u6bcf\u4e2a\u975e\u5185\u90e8\u7c7b\u548c\u51fd\u6570\r\n\r\n### Container Widget/\u5bb9\u5668\u63a7\u4ef6\r\n\r\n1. `Tk`: \u7a97\u53e3\u7c7b\r\n\r\n    \u7ee7\u627f\u4e8e`tkinter.Tk`\uff0c\u5728\u7ee7\u627f\u4e86`tkinter`\u6a21\u5757\u5185`Tk`\u7684\u57fa\u7840\u4e0a\uff0c\u53c8\u52a0\u5165\u4e86\u5bf9`tkintertools`\u6a21\u5757\u4e2d\u7684`Canvas`\u5bf9\u8c61\u7684\u652f\u6301\uff0c\u5e76\u52a0\u5165\u4e86\u68c0\u6d4b\u7a97\u53e3\u5927\u5c0f\u662f\u5426\u7f29\u653e\u7684\u673a\u5236\uff0c\u4ee5\u4f7f\u5f97\u5176\u5b50`Canvas`\u5747\u80fd\u6b63\u786e\u5730\u8fdb\u884c\u7f29\u653e\r\n\r\n2. `Toplevel`: \u9876\u7ea7\u7a97\u53e3\u7c7b\r\n\r\n    \u7ee7\u627f\u4e8e`tkinter.Toplevel`\u548c`Tk`\uff0c\u52a0\u5165\u4e86\u5bf9`tkintertools`\u6a21\u5757\u4e2d\u7684`Canvas`\u5bf9\u8c61\u7684\u652f\u6301\uff0c\u5176\u4f59\u5747\u4e0e`Tk`\u4e00\u6837\r\n\r\n3. `Canvas`: \u753b\u5e03\u7c7b\r\n\r\n    \u7ee7\u627f\u4e8e`tkinter.Canvas`\uff0c\u52a0\u5165\u4e86\u5bf9\u753b\u5e03\u865a\u62df\u63a7\u4ef6\u7684\u652f\u6301\uff0c\u540c\u65f6\u662f\u5404\u7c7b\u54cd\u5e94\u4e8b\u4ef6\u3001\u7f29\u653e\u63a7\u5236\u7684\u7ba1\u7406\u8005\uff0c\u4e5f\u5bf9`tkinter.Canvas`\u7684\u5b9e\u4f8b\u65b9\u6cd5\u6709\u4e00\u5b9a\u7684\u517c\u5bb9\u6027\r\n\r\n### Virtual Canvas Widget/\u865a\u62df\u753b\u5e03\u63a7\u4ef6\r\n\r\n1. `Label`: \u6807\u7b7e\u63a7\u4ef6\r\n\r\n    \u6807\u7b7e\u63a7\u4ef6\u7684\u529f\u80fd\u548c`tkinter.Label`\u7684\u529f\u80fd\u7c7b\u4f3c\uff0c\u4f46\u66f4\u52a0\u7684\u591a\u5143\u5316  \r\n    \u4e0b\u9762\u662f`Label`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a  \r\n\r\n    ![LabelTest.png](readme_res/LabelTest.png)\r\n\r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('LabelTest', 1000, 400)\r\n    canvas = tkt.Canvas(root, 1000, 400, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(510, 175, 480, 150)\r\n    tkt.Label(canvas, 50, 50, 400, 100, text='NormalLabel\\nHere is the text')\r\n    tkt.Label(canvas, 50, 200, 400, 100, radius=20, text='RoundCornerLabel')\r\n    tkt.Label(canvas, 550, 50, 400, 100, text='DisableLabel').set_live(False)\r\n    tkt.Label(canvas, 550, 200, 400, 100, radius=20,\r\n            text='TransparentLabel', color_fill=tkt.COLOR_NONE)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n2. `Button`: \u6309\u94ae\u63a7\u4ef6\r\n\r\n    \u6309\u94ae\u63a7\u4ef6\u76f8\u8f83\u4e8e`tkinter.Button`\uff0c\u5176\u81ea\u7531\u5ea6\u66f4\u9ad8\uff0c`tkinter.Button`\u53ea\u6709\u5728\u6309\u4e0b\u7684\u65f6\u5019\u624d\u80fd\u89e6\u53d1\u7ed1\u5b9a\u7684\u5173\u8054\u4e8b\u4ef6\uff0c\u800c`Button`\u5374\u53ef\u4ee5\u5728\u9f20\u6807\u79fb\u81f3\u6309\u94ae\u4e0a\u65b9\u65f6\u3001\u9f20\u6807\u6309\u4e0b\u65f6\u3001\u9f20\u6807\u677e\u5f00\u65f6\u90fd\u53ef\u4ee5\u7ed1\u5b9a\u5173\u8054\u4e8b\u4ef6  \r\n    \u4e0b\u9762\u662f`Button`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a\r\n\r\n    ![ButtonTest.png](readme_res/ButtonTest.png)\r\n\r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('ButtonTest', 500, 500)\r\n    canvas = tkt.Canvas(root, 500, 500, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(50, 280, 400, 100)\r\n    tkt.Button(canvas, 150, 135, 200, 50, text='NormalButton')\r\n    tkt.Button(canvas, 100, 195, 300, 50, radius=10, text='RoundCornerButton')\r\n    tkt.Button(canvas, 150, 255, 200, 50, text='DisableButton').set_live(False)\r\n    tkt.Button(canvas, 100, 315, 300, 50, radius=10,\r\n            text='TransparentButton', color_fill=tkt.COLOR_NONE)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n3. `CheckButton`: \u590d\u9009\u6846\u63a7\u4ef6\r\n\r\n    \u590d\u9009\u6846\u63a7\u4ef6\u76f8\u5bf9\u4e8e`tkinter`\u539f\u751f\u7684`tkinter.CheckButton`\u5728\u4f7f\u7528\u65b9\u9762\u66f4\u52a0\u5730\u7b80\u5355\uff0c\u540c\u65f6\u989c\u503c\u4e5f\u4e0a\u5347\u4e86\u4e0d\u5c11  \r\n    \u4e0b\u9762\u662f`CheckButton`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a\r\n\r\n    ![CheckButtonTest.png](readme_res/CheckButtonTest.png)\r\n\r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('CheckButtonTest', 500, 300)\r\n    canvas = tkt.Canvas(root, 500, 300, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(40, 190, 420, 50)\r\n    tkt.CheckButton(canvas, 50, 50, 30, text='NormalCheckButton', value=True)\r\n    tkt.CheckButton(canvas, 50, 100, 30, text='DisableCheckButton',\r\n                    value=True).set_live(False)\r\n    tkt.CheckButton(canvas, 50, 150, 30, radius=10, text='RoundCornerCheckButton')\r\n    tkt.CheckButton(canvas, 50, 200, 30, radius=15,\r\n                    text='TransparentCheckButton', color_fill=tkt.COLOR_NONE)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n4. `Entry`: \u8f93\u5165\u6846\u63a7\u4ef6\r\n\r\n    \u8f93\u5165\u6846\u63a7\u4ef6\u53ef\u4ee5\u8f7b\u677e\u5730\u8bbe\u7f6e\u8f93\u5165\u7684\u6587\u672c\u4f4d\u7f6e\uff08\u9760\u5de6\u3001\u5c45\u4e2d\u548c\u9760\u53f3\uff09\uff0c\u540c\u65f6\uff0c\u5b83\u53ef\u4ee5\u5728\u9f20\u6807\u79fb\u81f3\u8f93\u5165\u6846\u4e0a\u65b9\u3001\u9f20\u6807\u672a\u5728\u8f93\u5165\u6846\u4e0a\u65b9\u4e24\u79cd\u72b6\u6001\u663e\u793a\u4e0d\u540c\u7684\u9ed8\u8ba4\u6587\u672c  \r\n    \u4e0b\u9762\u662f`Entry`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a\r\n\r\n    ![EntryTest.png](readme_res/EntryTest.png)\r\n    \r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('EntryTest', 500, 400)\r\n    canvas = tkt.Canvas(root, 500, 400, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(50, 193, 400, 100)\r\n    tkt.Entry(canvas, 20, 20, 200, 30, text=('LeftEntry', 'Enter'))\r\n    tkt.Entry(canvas, 20, 55, 200, 30, text=(\r\n        'CenterEntry', 'Enter'), justify='center')\r\n    tkt.Entry(canvas, 20, 90, 200, 30, text=(\r\n        'RightEntry', 'Enter'), justify='right')\r\n    tkt.Entry(canvas, 270, 20, 200, 30, radius=8, text='LeftEntry')\r\n    tkt.Entry(canvas, 270, 55, 200, 30, radius=8,\r\n            text='CenterEntry', justify='center')\r\n    tkt.Entry(canvas, 270, 90, 200, 30, radius=8,\r\n            text='RightEntry', justify='right')\r\n    tkt.Entry(canvas, 100, 150, 300, 35, text=('PasswordEntry',\r\n            'Click To Enter'), justify='center', show='\u25cf')\r\n    tkt.Entry(canvas, 100, 200, 300, 35, text='DisableEntry',\r\n            justify='center').set_live(False)\r\n    tkt.Entry(canvas, 100, 250, 300, 35, text='TransparentEntry',\r\n            justify='center', color_fill=tkt.COLOR_NONE)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n5. `Text`: \u6587\u672c\u6846\u63a7\u4ef6\r\n\r\n    \u6587\u672c\u6846\u7c7b\u4f3c\u4e8e\u8f93\u5165\u6846\uff0c\u8fd9\u91cc\u5c31\u4e0d\u518d\u8d58\u8ff0  \r\n    \u4e0b\u9762\u662f`Text`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a\r\n\r\n    ![TextTest.png](readme_res/TextTest.png)\r\n    \r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('TextTest', 1000, 400)\r\n    canvas = tkt.Canvas(root, 1000, 400, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height) -> None:  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(510, 175, 480, 150)\r\n    tkt.Text(canvas, 50, 50, 400, 100, text=('NormalText(Left)', 'Click To Enter'))\r\n    tkt.Text(canvas, 50, 200, 400, 100, radius=20,\r\n            text='RoundCornerText(Center)', justify='center')\r\n    tkt.Text(canvas, 550, 50, 400, 100, text='DisableText').set_live(False)\r\n    tkt.Text(canvas, 550, 200, 400, 100, radius=20,\r\n            text='TransparentText(Right)', justify='right', color_fill=tkt.COLOR_NONE)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n6. `Progressbar`: \u8fdb\u5ea6\u6761\u63a7\u4ef6\r\n\r\n    \u8fdb\u5ea6\u6761\u63a7\u4ef6\u76f8\u6bd4`tkinter.ttk.Progressbar`\uff0c\u5916\u89c2\u4e0a\u7684\u81ea\u7531\u5ea6\u8f83\u5927  \r\n    \u4e0b\u9762\u662f`Progressbar`\u63a7\u4ef6\u7684\u5916\u89c2\uff1a\r\n\r\n    ![ProgressbarTest.png](readme_res/ProgressbarTest.png)\r\n\r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('ProgressbarTest', 500, 500)\r\n    canvas = tkt.Canvas(root, 500, 500, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height) -> None:  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#0000FF'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n\r\n\r\n    colorful(30, 290, 440, 50)\r\n    tkt.Progressbar(canvas, 50, 50, 400, 30)\r\n    tkt.Progressbar(canvas, 50, 100, 400, 30).load(.6667)\r\n    tkt.Progressbar(canvas, 50, 150, 400, 30, borderwidth=5).load(1)\r\n    (_ := tkt.Progressbar(canvas, 50, 200, 400, 30)).load(0.3333)\r\n    _.set_live(False)\r\n    tkt.Progressbar(canvas, 50, 250, 400, 30, color_bar=(\r\n        'lightyellow', 'skyblue')).load(.5)\r\n    tkt.Progressbar(canvas, 50, 300, 400, 30, color_bar=('', 'orange')).load(.1667)\r\n\r\n    progressbar = tkt.Progressbar(canvas, 50, 375, 400, 30)\r\n    progressbar_2 = tkt.Progressbar(canvas, 50, 425, 400, 30)\r\n\r\n\r\n    def load(total, count=0):  # type: (int, int) -> None\r\n        \"\"\" load progressbar \"\"\"\r\n        progressbar.load(count/total)\r\n        progressbar_2.load(1-count/total)\r\n        if count < total:\r\n            root.after(3, load, total, count+1)\r\n\r\n\r\n    load(10000)\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n### Tool Class/\u5de5\u5177\u7c7b\r\n\r\n1. `PhotoImage`: \u56fe\u7247\u7c7b\r\n\r\n    `PhotoImage`\u7c7b\u7ee7\u627f\u4e8e`tkinter.PhotoImage`\uff0c\u5b83\u662f\u5728`tkinter.PhotoImage`\u7684\u57fa\u7840\u4e0a\u505a\u529f\u80fd\u7684\u5f3a\u5316\uff0c\u5bf9 gif \u52a8\u56fe\u6709\u5f88\u597d\u7684\u652f\u6301\uff0c\u4ec5\u9700\u6781\u5c11\u91cf\u4ee3\u7801\u5373\u53ef\u5b9e\u73b0\u52a8\u56fe\u7684\u663e\u793a\uff0c\u8fd8\u53ef\u4ee5\u8bbe\u7f6e\u52a8\u56fe\u663e\u793a\u7684\u901f\u5ea6\uff0c\u6b64\u5916\uff0c\u5bf9 png \u7c7b\u578b\u7684\u56fe\u7247\u7684\u652f\u6301\u4e5f\u6709\u5f3a\u5316\uff0c\u53ef\u4ee5\u5728\u4e0d\u4f9d\u8d56\u4efb\u4f55\u7b2c\u4e09\u65b9\u6a21\u5757\u6216\u8005\u5e93\u7684\u60c5\u51b5\u4e0b\uff0c\u5bf9 png \u56fe\u7247\u8fdb\u884c\u7f29\u653e\r\n\r\n2. `Singleton`: \u5355\u4f8b\u6a21\u5f0f\u7c7b\r\n\r\n    \u5355\u4f8b\u6a21\u5f0f\uff0c\u4e0d\u7528\u4ecb\u7ecd\u4e86\u5427\uff1f\u901a\u8fc7\u7ee7\u627f\u5b83\u6765\u4f7f\u7528\r\n\r\n### Tool Function/\u5de5\u5177\u51fd\u6570\r\n\r\n1. `move`: <a name=\"move\">\u79fb\u52a8\u51fd\u6570</a>\r\n\r\n    \u79fb\u52a8\u51fd\u6570\u53ef\u4ee5\u8f7b\u677e\u5730\u6309\u4e00\u5b9a\u7684\u89c4\u5f8b\u3001\u79fb\u52a8\u901f\u5ea6\u3001\u79fb\u52a8\u65f6\u95f4\u53bb\u79fb\u52a8`tkintertools`\u6a21\u5757\u5185\u7684\u6240\u6709\u5bf9\u8c61\uff0c\u540c\u65f6\u517c\u5bb9\u4e86`tkinter`\u5185\u7684\u5bf9\u8c61\uff0c\u5373`tkinter`\u4e2d\u7684\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u79fb\u52a8\uff0c\u751a\u81f3\u5b83\u8fd8\u53ef\u4ee5\u79fb\u52a8\u7a97\u53e3\u7684\u4f4d\u7f6e\uff01\r\n\r\n    ![MoveTest.gif](readme_res/MoveTest.gif)\r\n    \r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('MoveTest', 500, 500)\r\n    canvas = tkt.Canvas(root, 500, 500, 0, 0)\r\n    rect = canvas.create_rectangle(50, 350, 150, 450)\r\n\r\n\r\n    def move_window(switch=[True]):  # type: (list[bool]) -> None\r\n        tkt.move(root, None, 1000 if switch[0] else -1000, 0, 800, mode='flat')\r\n        switch[0] = not switch[0]\r\n\r\n\r\n    def move_button(switch=[True]) -> None:  # type: (list[bool]) -> None\r\n        tkt.move(canvas, button, 200 if switch[0]\r\n                else -200, 0, 500, mode='rebound')\r\n        switch[0] = not switch[0]\r\n\r\n\r\n    def move_rect(switch=[True]):  # type: (list[bool]) -> None\r\n        tkt.move(canvas, rect, 200 if switch[0] else -200, 0, 500, mode='smooth')\r\n        switch[0] = not switch[0]\r\n\r\n\r\n    tkt.Button(canvas, 50, 50, 200, 40, radius=10,\r\n            text='MoveWindow', command=move_window)\r\n    tkt.Button(canvas, 50, 100, 200, 40, radius=10,\r\n            text='MoveRect', command=move_rect)\r\n    button = tkt.Button(canvas, 50, 150, 200, 40, radius=10,\r\n                        text='MoveButton', command=move_button)\r\n\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n2. `text`: \u6587\u672c\u51fd\u6570\r\n\r\n    \u53ef\u4ee5\u5feb\u901f\u5e76\u65b9\u4fbf\u5730\u5f97\u5230\u4e00\u4e2a\u53c2\u6570\u957f\u5ea6\u7684\u5b57\u7b26\u4e32\uff0c\u4e14\u5b57\u7b26\u4e32\u7684\u5185\u5bb9\u53ef\u4ee5\u6307\u5b9a\u4f4d\u7f6e  \r\n    \u5982\uff1a\u5f97\u5230\u4e00\u4e2a 20 \u957f\u5ea6\u7684\u5b57\u7b26\u4e32 \u201ctkintertools\u201d  \r\n    <pre>\r\n    `left`   : \"tkintertools        \"  \r\n    `center` : \"    tkintertools    \"  \r\n    `right`  : \"        tkintertools\"</pre>\r\n\r\n3. `color`: <a name=\"Gradient\">\u989c\u8272\u51fd\u6570</a>\r\n\r\n    \u989c\u8272\u51fd\u6570\u53ef\u4ee5\u8f7b\u677e\u6c42\u51fa\u4e00\u4e2a\u989c\u8272\u5230\u53e6\u5916\u4e00\u4e2a\u989c\u8272\u7684\u8fc7\u6e21\u989c\u8272\uff0c\u56e0\u6b64\u53ef\u4ee5\u8f7b\u677e\u5f97\u5230\u6e10\u53d8\u8272\u7684\u6548\u679c\uff0c\u540c\u65f6\uff0c\u6539\u53d8\u4f20\u5165\u7684\u53c2\u6570\u8fd8\u53ef\u4ee5\u5f97\u5230\u4f20\u5165\u989c\u8272\u7684\u5bf9\u6bd4\u8272  \r\n    \u7b2c\u4e8c\u5f20\u56fe\u662f test.py \u5728\u56fe\u50cf\u6d4b\u8bd5\u4e2d\u7ed8\u5236\u7684\u56fe\u6848\r\n\r\n    ![ColorTest.png](readme_res/ColorTest.png)\r\n\r\n    ![Test_Draw.png](readme_res/Test_Draw.png)\r\n\r\n    <details><summary><b>\u6e90\u4ee3\u7801</b></summary>\r\n\r\n    ```python\r\n    import tkintertools as tkt\r\n\r\n    root = tkt.Tk('ColorTest', 500, 500)\r\n    canvas = tkt.Canvas(root, 500, 500, 0, 0)\r\n\r\n\r\n    def colorful(x, y, width, height):  # type: (int, int, int, int) -> None\r\n        \"\"\" Gradient colors \"\"\"\r\n        for i in range(width):\r\n            color = tkt.color(('#FF0000', '#00FF00'), i/width)\r\n            color_2 = tkt.color(('#FFFFFF', '#000000'), i/width)\r\n            canvas.create_line(x+i, y, x+i, y+height, fill=color)\r\n            canvas.create_oval(250-i/3, 300-i/3, 250+i/3, 300 +\r\n                            i/3, outline=color_2, width=2)\r\n\r\n\r\n    colorful(50, 50, 400, 100)\r\n    root.mainloop()\r\n    ```\r\n\r\n    </details>\r\n\r\n4. `askfont`: \u5b57\u4f53\u9009\u62e9\u5bf9\u8bdd\u6846\r\n\r\n    `askfont`\u51fd\u6570\u53ef\u4ee5\u6253\u5f00\u9ed8\u8ba4\u7684\u5b57\u4f53\u9009\u62e9\u7a97\u53e3\uff0c\u8fd9\u4e2a\u7a97\u53e3\u867d\u7136\u662f\u9ed8\u8ba4\u7684\uff0c\u4f46\u5b83\u5b9e\u9645\u4e0a\u65e0\u6cd5\u5728`tkinter`\u4e2d\u6253\u5f00\uff0c\u56e0\u4e3a`tkinter`\u5e76\u6ca1\u6709\u5bf9\u5e94\u7684 API \u80fd\u591f\u505a\u5230\u8fd9\u4e00\u70b9\u3002\u4f46\u662f\uff0c`tkintertools`\u8c03\u7528\u5e76\u5c01\u88c5\u4e86\u539f\u751f\u7684 tcl \u7684\u547d\u4ee4\uff0c\u4f7f\u5f97\u5b57\u4f53\u9009\u62e9\u6846\u80fd\u591f\u88ab\u6211\u4eec\u4f7f\u7528\u3002\r\n\r\n    ![font.png](readme_res/font.png)\r\n\r\n5. `SetProcessDpiAwareness`: <a name=\"DPI\">DPI \u7ea7\u522b\u8bbe\u7f6e\u51fd\u6570</a>\r\n\r\n    \u8fd9\u4e2a\u51fd\u6570\u5b9e\u9645\u4e0a\u53ea\u662f\u5bf9\u51fd\u6570`ctypes.WinDLL('shcore').SetProcessDpiAwareness`\u7684\u4e00\u4e2a\u7b80\u5355\u5305\u88c5\uff0c\u5176\u503c\u53ef\u4e3a 0\u30011 \u548c 2\uff0c\u5206\u522b\u4ee3\u8868\u7a0b\u5e8f DPI \u7684\u4e0d\u540c\u7ea7\u522b\uff0c\u90a3\u4e48\u7f29\u653e\u6548\u679c\u4e5f\u5c31\u4e0d\u540c\uff0c`tkintertools`\u9009\u62e9\u7684\u503c\u662f 1\uff0c\u4f46\u7a0b\u5e8f\u9ed8\u8ba4\u503c\u5b9e\u9645\u4e3a 0  \r\n    \u4e0b\u9762\u662f\u672a\u6267\u884c\u8fd9\u4e2a\u51fd\u6570\u7684\u6548\u679c\r\n    \r\n    ![SetProcessDpiAwareness_0.png](readme_res/SetProcessDpiAwareness_0.png)\r\n\r\n    <p>\u4e0b\u9762\u662f\u6267\u884c\u4e86\u8fd9\u4e2a\u51fd\u6570\u7684\u6548\u679c</p>\r\n\r\n    ![SetProcessDpiAwareness_1.png](readme_res/SetProcessDpiAwareness_1.png)\r\n\r\n    \u4ece\u4e0a\u9762\u7684\u4e24\u5f20\u56fe\u4e2d\u53ef\u4ee5\u5f88\u660e\u663e\u7684\u770b\u51fa\u7b2c\u4e00\u5f20\u5f88\u6a21\u7cca\uff0c\u7b2c\u4e8c\u5f20\u5f88\u6e05\u6670\uff0c\u8fd9\u5c31\u662f DPI \u7ea7\u522b\u4e0d\u540c\u7684\u539f\u56e0\uff0c\u4e0d\u8fc7\u8fd9\u4e00\u70b9\u5728\u5c4f\u5e55\u7f29\u653e\u6bd4\u4e0d\u662f 100% \u7684\u65f6\u5019\u624d\u4f1a\u51fa\u73b0  \r\n    \u5927\u5bb6\u5bf9\u4e0a\u9762\u7684\u56fe\u80af\u5b9a\u5f88\u719f\u6089\uff0c\u8fd9\u4e0d\u5c31\u662f IDLE \u5417\uff01\uff1f\u5bf9\uff0c\u8fd9\u4e2a\u7684\u95ee\u9898\u7684\u89e3\u51b3\u529e\u6cd5\u4e5f\u662f\u6765\u81ea\u4e8e IDLE \u7684\u6e90\u4ee3\u7801 [pyshell.py line 18~20]  \r\n    \u6ce8\u610f\uff1a\u8be5\u51fd\u6570\u5728\u7a0b\u5e8f\u7684\u4e0d\u540c\u4f4d\u7f6e\u6267\u884c\u7684\u6548\u679c\u4e0d\u4e00\u6837\uff01\u4e00\u822c\u7528\u5728`mainloop`\u4e4b\u524d\uff0c\u4f46`tkintertools`\u5df2\u7ecf\u5728`mainloop`\u51fd\u6570\u4e2d\u5d4c\u5165\u4e86\u8be5\u51fd\u6570\uff0c\u65e0\u9700\u518d\u8bbe\u7f6e\u4e00\u6b21 DPI \u7ea7\u522b\uff0c\u6b64\u51fd\u6570\u662f\u4e3a\u4e86\u539f\u751f`tkinter`\u7a0b\u5e8f\u7528\u7684\u3002\r\n\r\nExamples/\u5b9e\u6218\u793a\u4f8b\r\n----------------\r\n\r\n\u4ee5\u4e0b\u4e09\u4e2a\u4e3a\u4f7f\u7528\u4e86 tkintertools \u7684\u5178\u578b\u6848\u4f8b\uff0c\u4f9b\u5927\u5bb6\u53c2\u8003\uff0c\u7a0b\u5e8f\u5747\u514d\u8d39\uff0c\u6e90\u4ee3\u7801\u5f00\u653e\uff01  \r\n\u524d\u9762\u4e24\u4e2a\u662f\u6211\u4e00\u8fb9\u6539\u8fdb tkintertools \u6a21\u5757\uff0c\u4e00\u8fb9\u5199\u7684\u5b9e\u6218\uff0c\u6709\u4e00\u5b9a\u7684 bug\uff0c\u4f46\u4e0d\u5f71\u54cd\u6b63\u5e38\u4f7f\u7528\u3002  \r\n\u53ea\u6709\u628a\u6a21\u5757\u771f\u6b63\u5730\u7528\u5230\u5b9e\u6218\u4e0a\u53bb\uff0c\u624d\u77e5\u9053\u54ea\u6709 bug\uff0c\u54ea\u91cc\u8fd8\u9700\u8981\u6539\u8fdb\uff01\r\n\r\n### \u4efb\u52a1\u6e05\u5355\u5c0f\u5de5\u5177\r\n\r\n* \u6587\u7ae0\u94fe\u63a5: https://xiaokang2022.blog.csdn.net/article/details/128561339\r\n* \u4ee3\u7801\u4ed3\u5e93: https://gitcode.net/weixin_62651706/todolist\r\n* \u7a0b\u5e8f\u4e0b\u8f7d(\u542b\u6253\u5305\u597d\u7684\u7a0b\u5e8f\u548c\u6e90\u4ee3\u7801): https://wwc.lanzoum.com/iyxL30kpkcbe\r\n* \u63a8\u8350\u6307\u6570: \ud83d\udc4d\r\n\r\n\u8fd9\u4e2a\u6848\u4f8b\u4f7f\u7528\u4e86 tkintertools-v2.5.7 \u7248\u672c\uff08\u65b0\u7248\u5df2\u65e0\u6cd5\u517c\u5bb9\uff09\uff0c\u542b\u6709\u4e00\u4e9b bug\uff0c\u5927\u91cf\u91c7\u7528\u4e86 tkintertools \u7684\u63a7\u4ef6\uff0c\u53d6\u5f97\u4e86\u6bd4\u8f83\u597d\u7684\u754c\u9762\u6548\u679c\u3002\u4f53\u73b0\u4e86 tkintertools \u6a21\u5757\u4e0e tkinter \u6a21\u5757\u76f8\u6bd4\u5728\u989c\u503c\u4e0a\u7684\u78be\u538b\u6027\uff01\r\n\r\n![todolist.gif](https://img-blog.csdnimg.cn/img_convert/dc1a598c3f082253c1ebc7bbca0b98ce.gif)\r\n\r\n![todolist.gif](https://img-blog.csdnimg.cn/img_convert/7f34451deda1af13712a9edcb37f20b4.gif)\r\n\r\n### \u4e2d\u56fd\u8c61\u68cb\u6e38\u620f\r\n\r\n* \u6587\u7ae0\u94fe\u63a5: https://xiaokang2022.blog.csdn.net/article/details/128852029\r\n* \u4ee3\u7801\u4ed3\u5e93: https://gitcode.net/weixin_62651706/chess\r\n* \u7a0b\u5e8f\u4e0b\u8f7d(\u542b\u6253\u5305\u597d\u7684\u7a0b\u5e8f\u548c\u6e90\u4ee3\u7801): https://wwc.lanzoum.com/iwgp00mlewpa\r\n* \u63a8\u8350\u6307\u6570: \ud83d\udc4d\ud83d\udc4d\r\n\r\n\u6ce8\u610f\uff1a\u6e90\u4ee3\u7801\u6709\u89e3\u538b\u5bc6\u7801\uff0c\u89e3\u538b\u5bc6\u7801\u5728\u94fe\u63a5\u6587\u7ae0\u4e2d\uff0c\u8bf7\u4ed4\u7ec6\u67e5\u627e\uff01  \r\n\u8fd9\u4e2a\u6848\u4f8b\u4f7f\u7528\u4e86 tkintertools-v2.5.9.5 \u7248\u672c\uff08\u65b0\u7248\u5df2\u65e0\u6cd5\u517c\u5bb9\uff09, \u542b\u6709\u5c11\u91cf bug\uff0c\u90e8\u5206 UI \u91c7\u7528\u4e86 tkintertools\uff0c\u90e8\u5206 UI \u91c7\u7528\u4e86 tkinter\uff0c\u5c5e\u4e8e\u6df7\u5408\u4f7f\u7528\u3002\u4f53\u73b0\u4e86 tkintertools \u6a21\u5757\u5bf9 tkinter \u6a21\u5757\u7684\u517c\u5bb9\u6027\uff01\r\n\r\n![chess.png](https://img-blog.csdnimg.cn/43df0568d4b34078a443a098b67c126a.png)\r\n\r\n![chess.png](https://img-blog.csdnimg.cn/fc768093715d47d7b14bea015a921e3d.png)\r\n\r\n### \u7b80\u6613\u767b\u5f55\u754c\u9762\r\n\r\n* \u6587\u7ae0\u94fe\u63a5: \u6682\u65e0\r\n* \u4ee3\u7801\u4ed3\u5e93: https://gitcode.net/weixin_62651706/tester\r\n* \u7a0b\u5e8f\u4e0b\u8f7d: \u6682\u65e0\r\n* \u63a8\u8350\u6307\u6570: \ud83d\udc4d\ud83d\udc4d\ud83d\udc4d\r\n\r\n\u8fd9\u4e2a\u6848\u4f8b\u4f7f\u7528\u4e86\u6700\u65b0\u7a33\u5b9a\u7248\u7684 tkintertools-v2.6.0\uff0c\u754c\u9762\u975e\u5e38\u7a33\u5b9a\uff0c\u51e0\u4e4e\u6ca1\u6709 bug\uff0c\u5b8c\u5168\u91c7\u7528 tkintertools \u7684\u63a7\u4ef6\uff0c\u989c\u503c\u5f88\u9ad8\uff0c\u754c\u9762\u975e\u5e38\u6d41\u7545\u3002\u4f53\u73b0\u4e86 tkintertools \u6a21\u5757\u4e0e tkinter \u6a21\u5757\u76f8\u6bd4\u5728\u6027\u80fd\u4e0a\u7684\u4f18\u8d8a\u6027\uff01\r\n\r\n![exam3_1.png](readme_res/exam3_1.png)\r\n\r\n![exam3_2.png](readme_res/exam3_2.png)\r\n\r\nMore/\u66f4\u591a\r\n---------\r\n\r\n> GitHub:  \r\n> https://github.com/Xiaokang2022/tkintertools\r\n\r\n> Gitee(Mirror/\u955c\u50cf):  \r\n> https://gitee.com/xiaokang-2022/tkintertools\r\n\r\n> GitCode(Mirror/\u955c\u50cf):  \r\n> https://gitcode.net/weixin_62651706/tkintertools\r\n\r\n\u8fd8\u6709\u66f4\u591a\u5185\u5bb9\u8bf7\u5728 [\u6e90\u4ee3\u7801](tkintertools/) \u4e2d\u63a2\u7d22\uff01\r\n",
    "bugtrack_url": null,
    "license": "MulanPSL-2.0",
    "summary": "An auxiliary module of the tkinder module",
    "version": "2.6.5",
    "project_urls": {
        "Homepage": "https://github.com/Xiaokang2022/tkintertools"
    },
    "split_keywords": [
        "tkinter",
        "tkintertools",
        "gui"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7eab0fe6c025830fb1b46543d27213cf6ff2940684914c2344e793eeb4432663",
                "md5": "9160fa105fa099dc88a571468a67c304",
                "sha256": "e68592a6bd703a0c4c752fffce38fe708d368e58b2c03e11008b9bdabd6eab76"
            },
            "downloads": -1,
            "filename": "tkintertools_dev-2.6.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9160fa105fa099dc88a571468a67c304",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 36013,
            "upload_time": "2023-06-13T06:31:47",
            "upload_time_iso_8601": "2023-06-13T06:31:47.830874Z",
            "url": "https://files.pythonhosted.org/packages/7e/ab/0fe6c025830fb1b46543d27213cf6ff2940684914c2344e793eeb4432663/tkintertools_dev-2.6.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "24ab736e49cdca517e7e93645ae1e599d232e2872a3230456ee804cd31272cc0",
                "md5": "f49c2ef119eb14f0c1621d62b1ec556f",
                "sha256": "32aedded9dbe8f6b859735743db6ecb9dc8640da62594af9c59adfa5b29eb3d4"
            },
            "downloads": -1,
            "filename": "tkintertools-dev-2.6.5.tar.gz",
            "has_sig": false,
            "md5_digest": "f49c2ef119eb14f0c1621d62b1ec556f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 44182,
            "upload_time": "2023-06-13T06:31:52",
            "upload_time_iso_8601": "2023-06-13T06:31:52.035577Z",
            "url": "https://files.pythonhosted.org/packages/24/ab/736e49cdca517e7e93645ae1e599d232e2872a3230456ee804cd31272cc0/tkintertools-dev-2.6.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-13 06:31:52",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Xiaokang2022",
    "github_project": "tkintertools",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "tkintertools-dev"
}
        
Elapsed time: 0.65211s