<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"
}