社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

精通 CustomTkinter:轻松构建精美的 Python GUI

数据STUDIO • 5 月前 • 298 次点击  


创建简洁响应式的 Python 应用:CustomTkinter 全面指南

你是否也曾陷入这样的困境:用Python开发了一个功能强大的工具,但用户反馈却是“界面太丑了”、“用起来不够顺手”?

作为一名Pythoner,我们常常面临这样的尴尬——功能实现了,逻辑完美了,但那个基于标准Tkinter的界面,怎么看都像是从Windows 98时代穿越过来的。按钮方方正正,颜色单调乏味,布局死板僵硬……

别担心,今天云朵君要向你介绍一个能彻底改变局面的神器:CustomTkinter!

为什么我们需要CustomTkinter?

在深入代码之前,我们先来聊聊为什么标准Tkinter无法满足现代应用的需求。

想象一下,你正在开发一个数据分析工具。你的算法很先进,数据处理很高效,但当你把工具交给用户时,他们的第一反应却是:“这界面也太老了吧?” 第一印象至关重要,而Tkinter默认的界面风格,往往给人“业余”或“过时”的感觉。

CustomTkinter应运而生,它就像一个 现代化的装修队,给老旧的Tkinter房子做了全面翻新。保留了原本坚固的“地基”(Tkinter的稳定性和跨平台性),却换上了时尚的“外立面”和“室内装修”。

快速对比:Tkinter vs CustomTkinter

在深入学习 Python CustomTkinter 之前,掌握 Tkinter 的基础知识至关重要。Tkinter 是 Python 的事实标准 GUI 工具包,它提供了用于创建窗口、对话框、按钮和其他 GUI 元素的工具。Tkinter 提供了一种简单直接的界面构建方式,而 CustomTkinter 更进一步,它允许开发者自定义应用程序外观和交互方式的方方面面。

让我们直观感受一下区别。先看传统的Tkinter按钮:

import tkinter as tk

root = tk.Tk()
root.title("传统Tkinter界面")

# 传统Tkinter按钮 - 方方正正,缺乏现代感
btn_old = tk.Button(root, text="点击我", bg="SystemButtonFace", fg="black")
btn_old.pack(pady=20)

root.mainloop()

现在看看CustomTkinter的按钮:

import customtkinter as ctk

# 设置外观模式 - 支持"light", "dark", "system"
ctk.set_appearance_mode("dark")
# 设置颜色主题 - 内置blue, green, dark-blue等
ctk.set_default_color_theme("blue")

app = ctk.CTk()
app.title("现代CustomTkinter界面")

# 现代风格的按钮 - 圆角、渐变、悬停效果
btn_new = ctk.CTkButton(app, text="点击我", corner_radius=10)
btn_new.pack(pady=20)

app.mainloop()

运行这两段代码,你会发现视觉差异是巨大的!CustomTkinter的按钮拥有圆角设计、现代化的颜色渐变,甚至还有悬停效果——所有这些,只需要改变一行导入语句和简单的参数设置

自定义Tkinter

CustomTkinter 是一个 Python 库,它提供了一系列全新、现代且完全可定制的控件。这些控件的使用方式与普通的 Tkinter 控件完全相同,甚至可以与它们组合使用。该库支持高 DPI 缩放,并能根据系统外观或手动设置的模式(“浅色”、“深色”)进行调整。这使其成为在所有平台(Windows、macOS、Linux)上创建外观一致且现代化的桌面应用程序的理想工具。

CustomTkinter 的主要特性:

  • 现代小部件:一系列时尚的按钮、标签、边框等,设计时充分考虑了现代美学。
  • 无缝定制:微调颜色、边框、内边距和其他视觉元素,以实现统一且个性化的外观。
  • 轻松切换主题:轻松切换浅色和深色模式,或创建自定义主题以匹配您的品牌形象。
  • 高 DPI 支持:确保在各种平台的高分辨率显示器上呈现清晰锐利的视觉效果。
  • 熟悉的语法:利用您现有的 Tkinter 知识,通过几乎相同的语法轻松上手。

理论说得再多,不如亲手试试。让我们从一个完整的示例开始,感受CustomTkinter的便捷。

第一步:安装CustomTkinter

# 使用pip安装
pip install customtkinter

# 如果需要更新到最新版
pip install customtkinter --upgrade

第二步:创建你的第一个现代化应用

import customtkinter as ctk
import tkinter as tk  # 仍然可以混合使用传统Tkinter组件

class ModernApp:
    def __init__(self):
        # 初始化窗口
        self.app = ctk.CTk()
        self.app.title("我的现代化应用")
        self.app.geometry("400x300")
        
        # 设置主题(深色/浅色)
        ctk.set_appearance_mode("dark")  # 试试改为"light"或"system"
        ctk.set_default_color_theme("blue")  # 内置主题:blue, green, dark-blue
        
        self.create_widgets()
        
    def create_widgets(self):
        """创建界面组件"""
        # 标题标签
        title_label = ctk.CTkLabel(
            self.app, 
            text="欢迎使用现代化Python应用",
            font=("Arial"20"bold")
        )
        title_label.pack(pady=20)
        
        # 输入框
        self.entry = ctk.CTkEntry(
            self.app,
            placeholder_text="请输入内容...",
            width=250
        )
        self.entry.pack(pady=10)
        
        # 带图标的按钮
        button = ctk.CTkButton(
            self.app,
            text="提交",
            command=self.on_submit,
            corner_radius=10,
            hover_color="#2FA572"# 自定义悬停颜色
        )
        button.pack(pady=20)
        
        # 进度条
        self.progressbar = ctk.CTkProgressBar(self.app, width=250)
        self.progressbar.pack(pady=10)
        self.progressbar.set(0)  # 初始值为0
        
        # 开关控件
        self.switch = ctk.CTkSwitch(
            self.app, 
            text="启用高级功能",
            command=self.on_switch_toggle
        )
        self.switch.pack(pady=10)
        
    def on_submit(self):
        """按钮点击事件"""
        text = self.entry.get()
        if text:
            # 模拟进度条加载
            self.progressbar.start()
            self.app.after(2000lambda: self.show_completion(text))
    
    def on_switch_toggle(self):
        """开关切换事件"""
        state = "开启"if self.switch.get() else"关闭"
        print(f"高级功能已{state}")
    
    def show_completion(self, text):
        """显示完成状态"""
        self.progressbar.stop()
        self.progressbar.set(1)  # 设置为100%
        
        # 显示完成对话框
        dialog = ctk.CTkInputDialog(
            text=f"你输入的内容是: {text}\n\n请输入反馈:",
            title="完成"
        )
        response = dialog.get_input()
        if response:
            print(f"用户反馈: {response}")
    
    def run(self):
        """运行应用"""
        self.app.mainloop()

# 启动应用
if __name__ == "__main__":
    app = ModernApp()
    app.run()

运行这个应用,你会立即感受到:

  1. 深色主题:现代应用的标准配置,保护眼睛的同时也更显专业
  2. 圆角设计:所有组件都有适当的圆角,符合现代UI设计趋势
  3. 平滑动画:进度条有平滑的动画效果
  4. 一致风格:所有组件保持统一的视觉风格

CustomTkinter 核心组件

CustomTkinter 的主要优势之一是能够创建具有独特外观和行为的自定义控件。让我们来看一个使用 CustomTkinter 创建自定义按钮的示例。

import tkinter as tk 
import customtkinter as ctk 

# 创建一个自定义样式的按钮
root = tk.Tk() 
custom_button = ctk.CTkButton(root, text= "自定义按钮" , borderwidth= 2 , round = 10 ) 
custom_button.pack() 

# 运行主循环
root.mainloop()

在这个例子中,我们创建了一个具有指定边框宽度和圆角的自定义按钮,展示了 CustomTkinter 提供的灵活性。

探索自定义选项

CustomTkinter 提供了丰富的自定义选项,包括修改外观、行为和事件处理。一些主要的自定义选项包括:

  • 修改外观:通过调整颜色、边框和尺寸来自定义小部件的外观。
  • 行为自定义:为控件定义自定义行为,例如处理鼠标事件和用户交互。
  • 事件处理:自定义小部件的事件处理,允许开发人员定义响应用户事件的特定操作。

不同用例的代码示例

为了说明如何针对不同的使用场景实现自定义组件,我们来看几个代码示例:

1. 自定义按钮外观:

import tkinter as tk 
import customtkinter as ctk 

root = tk.Tk() 
custom_button = ctk.CTkButton(root, text= "自定义按钮" , borderwidth= 2 , round = 10 ) 
custom_button.pack() 
root.mainloop()

2. 处理自定义事件:

import tkinter as tk 
import customtkinter as ctk 

def custom_button_clicked(event): 
    print( "自定义按钮被点击!"

root = tk.Tk() 
custom_button = ctk.CTkButton(root, text= "自定义按钮" ) 
custom_button.bind( "" , custom_button_clicked) 
custom_button.pack() 
root.mainloop()

3. 创建自定义按钮:

button = ctk.CTkButton(app, text= "点击我!" )

4. 点击按钮时颜色发生变化:

def on_click (): 
    button.config(fg="red" ) 

button = ctk.CTkButton(app, text="点击我!", command=on_click)

5. 创建自定义复选框:

checkbox = ctk.CTkCheckBox(app, text="检查我!" )

6. 创建自定义单选按钮:

radiobutton = ctk.CTkRadioButton(app, text="选择我!" )

7. 自定义外观

custom_label = ctk.CustomLabel(root, text="自定义标签" , font=( "Helvetica" , 16 ))

8. 改变行为

custom_entry = ctk.CustomEntry(root, validate= "key" , validatecommand=my_validation_function)

9. 使用主题进行高级外观自定义

# 应用预定义主题
ctk.set_theme("dark_theme"

# 创建主题按钮
themed_button = ctk.CustomButton(root, text="主题按钮" ) 
themed_button.pack()

10. 行为调整

# 创建一个具有修改行为的自定义复选框
class CustomCheckbox (ctk.CustomCheckbox): 
    def  __init__(self, master= None , **kwargs ): 
        super().__init__(master, **kwargs) 
        self.config(command=self.toggle_state) 

    def toggle_state(self): 
        print( f"复选框状态:{self.get()}" ) 

# 实现自定义复选框
custom_checkbox = CustomCheckbox(root, text="自定义复选框" ) 
custom_checkbox.pack()

11. 创建自定义输入框小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义输入框示例"

entry = ctk.CTkEntry(app) 
entry.grid(row=0 , column=0 , padx=20 , pady=20

app.mainloop()

这段代码会创建一个带有自定义输入框的窗口,您可以在其中输入文本。

12. 创建自定义标签小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义标签控件示例"

label = ctk.CTkLabel(app, text="这是一个自定义标签" ) 
label.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义标签控件的窗口,用于显示文本。

13. 创建自定义滑块小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义滑块组件示例" ) 

slider = ctk.CTkSlider(app) 
slider.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义滑块控件的窗口,您可以通过滑动滑块来选择一个值。

14. 创建自定义进度条小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义进度条控件示例"

progress_bar = ctk.CTkProgressBar(app)
progress_bar.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义进度条控件的窗口。

15. 创建自定义滚动条小部件:

import customtkinter as ctk 

app = ctk.CTk () 
app.title( "自定义滚动条组件示例" ) 
scrollbar = ctk.CTkScrollbar (app) 
scrollbar.grid(row=0, column=0, padx=20, pady=20
app.mainloop()

这段代码会创建一个带有自定义滚动条控件的窗口。

16. 创建自定义文本组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义文本控件示例" ) 

text = ctk.CTkText(app) 
text.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

17. 创建自定义复选框按钮组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义复选框按钮组件示例" ) 

check_button = ctk.CTkCheckButton(app, text= "选中我!" ) 
check_button.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义复选框按钮控件的窗口。

18. 创建自定义单选按钮组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义单选按钮组件示例"

radio_button = ctk.CTkRadioButton(app, text="选择我!"
radio_button.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义单选按钮控件的窗口。

19. 创建自定义旋转框小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义微调框组件示例"

spin_box = ctk.CTkSpinbox(app) 
spin_box.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义微调框控件的窗口。

20. 创建自定义列表框小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title(  "自定义列表框组件示例" ) 

list_box = ctk.CTkListbox(app) 
list_box.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义列表框控件的窗口。

21. 创建自定义菜单小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义菜单控件示例" ) 

menu = ctk.CTkMenu(app) 
menu.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义菜单控件的窗口。

22. 创建自定义比例控件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义缩放控件示例" ) 

scale = ctk.CTkScale(app) 
scale.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义缩放控件的窗口。

23. 创建自定义选项菜单小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义选项菜单组件示例"

option_menu = ctk.CTkOptionMenu(app, ["选项 1""选项 2""选项 3"]) 
option_menu.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义选项菜单控件的窗口。

24. 创建自定义消息小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义消息组件示例" ) 

message = ctk.CTkMessage(app, text="这是一条自定义消息"  ) 
message.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义消息控件的窗口。

25. 创建自定义框架小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义框架组件示例" ) 

frame = ctk.CTkFrame(app) 
frame.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义框架控件的窗口。

26. 创建自定义画布组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义画布组件示例"

canvas = ctk.CTkCanvas(app) 
canvas.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义画布控件的窗口。

27. 创建自定义滚动文本组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义滚动文本控件示例" ) 

scroll_text = ctk.CTkScrollText(app) 
scroll_text.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义滚动文本控件的窗口。

28. 创建自定义笔记本小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义笔记本组件示例" ) 

notebook = ctk.CTkNotebook(app) 
notebook.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义笔记本控件的窗口。

29. 创建自定义窗格窗口小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义窗格窗口组件示例" ) 

paned_window = ctk.CTkPanedWindow(app) 
paned_window.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义窗格窗口控件的窗口。

30. 创建自定义树状视图小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义树状视图组件示例" ) 

tree_view = ctk.CTkTreeView(app) 
tree_view.grid(row=0, column=0, padx=20, pady=20

app.mainloop()

这段代码会创建一个带有自定义树状视图控件的窗口。

31. 创建自定义滚动条小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title("自定义滚动条组件示例"

scroll_bar = ctk.CTkScrollbar(app) 
scroll_bar.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义滚动条控件的窗口。

32. 创建自定义组合框组件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义组合框组件示例" ) 

combo_box = ctk.CTkCombobox(app) 
combo_box.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义组合框控件的窗口。

33. 创建自定义尺寸的握把小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义尺寸控制小部件示例" ) 

size_grip = ctk.CTkSizegrip(app) 
size_grip.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义大小控制柄控件的窗口。

34. 创建自定义分隔符小部件:

import customtkinter as ctk 

app = ctk.CTk() 
app.title( "自定义分隔符小部件示例" ) 

separator = ctk.CTkSeparator(app) 
separator.grid(row=0, column=0, padx=20, pady=20)  

app.mainloop()

这段代码会创建一个带有自定义分隔符控件的窗口。

请记住,这些只是基本示例。CustomTkinter 为每个组件提供了更多自定义选项,例如更改颜色、字体、大小以及添加自定义事件处理程序。请务必查看 CustomTkinter 文档以获取更多信息。

CustomTkinter 中的事件处理和回调函数

CustomTkinter 处理事件和回调函数的方式与 Tkinter 类似,但更加灵活。以下是简要概述:

  • 绑定事件:CustomTkinter 中的控件可以使用该bind方法绑定到特定事件(例如,按钮点击、按键)。
  • 自定义回调函数:开发者可以定义自定义回调函数来处理事件。这些函数可以根据用户交互进行定制,以执行特定操作。
  • 事件对象:回调函数接收一个事件对象,其中包含有关事件的信息,例如涉及的控件和事件类型。
def  custom_callback ( event ): 
    print(f"事件类型:{event.type },控件:{event.widget}" ) 

custom_button = ctk.CustomButton(root, text= "点击我" ) 
custom_button.bind("" , custom_callback)

设计模式和架构考量

使用 CustomTkinter 开发自定义小部件时,请考虑以下设计模式和架构注意事项:

  1. MVC(模型-视图-控制器):将应用程序逻辑(控制器)、可视化表示(视图)和数据(模型)分离,以增强可维护性和模块化。
  2. 观察者模式:实现观察者模式可以更高效地处理事件。组件可以订阅特定事件并做出相应的反应。
  3. 自定义小部件层级结构:将自定义小部件组织成层级结构,以保持清晰、合乎逻辑的排列,便于维护和理解。
  4. 文档:详细记录自定义小部件、其方法和参数,以便更好地协作和将来参考。

使用 CustomTkinter 的复杂 GUI 应用程序示例

设想一个使用 CustomTkinter 创建的自定义仪表板的数据可视化工具。该应用程序集成了图表、表格和交互式组件,用于探索和分析大型数据集。CustomTkinter 的自定义功能有助于创建用户友好且美观的界面。

class  DataVisualizationApp: 
    def __init__(self, master):
        # 用于图表、表格和交互式控件的自定义控件
        self.chart_widget = ctk.CustomChartWidget(master, data=data_source) 
        self.table_widget = ctk.CustomTableWidget(master, data=data_source) 
        self.controls_widget = ctk.CustomControlsWidget(master, callback=self.update_visualizations) 

        # 打包控件并设置布局
        self.chart_widget.pack() 
        self.table_widget.pack() 
        self.controls_widget.pack() 

    def update_visualizations(self, filters):
        # 根据用户选择的筛选条件更新图表和表格
        # 用于数据操作和可视化更新的自定义逻辑
        pass

# 初始化应用程序
root = tk.Tk() 
app = DataVisualizationApp(root) 
root.mainloop()

高效使用的最佳实践和技巧

在使用 CustomTkinter 时,遵循最佳实践至关重要,以确保高效使用和代码可维护性。一些最佳实践包括:

  • 统一的样式:在自定义小部件中保持统一的样式,以确保用户界面的一致性。
  • 重用自定义组件:寻找重用自定义组件的机会,以最大限度地减少代码重复。
  • 文档:记录自定义项和行为,以帮助代码维护和协作。

遵循这些最佳实践有助于在 GUI 开发中有效利用 CustomTkinter。

掌握了基础组件后,让我们看看如何用CustomTkinter打造真正专业级的应用。

技巧1:主题切换(深色/浅色模式)

上下滑动查看更多源码

import customtkinter as ctk

classThemeSwitcherApp:
    def__init__(self):
        self.app = ctk.CTk()
        self.app.geometry("500x400")
        self.app.title("主题切换示例")
        
        # 当前主题
        self.current_theme = "dark"
        
        self.create_widgets()
    
    defcreate_widgets(self):
        """创建界面组件"""
        # 标题
        title = ctk.CTkLabel(
            self.app,
            text="主题切换演示",
            font=("Arial"24"bold")
        )
        title.pack(pady=30)
        
        # 主题切换按钮
        self.theme_btn = ctk.CTkButton(
            self.app,
            text="切换到浅色模式",
            command=self.toggle_theme,
            width=200,
            height=40
        )
        self.theme_btn.pack(pady=20)
        
        # 显示当前主题的示例组件
        self.create_example_widgets()
    
    defcreate_example_widgets(self):
        """创建示例组件展示主题效果"""
        frame = ctk.CTkFrame(self.app)
        frame.pack(pady=30, padx=40, fill="both", expand=True)
        
        # 各种组件示例
        ctk.CTkLabel(frame, text="这是一个标签").pack(pady=10)
        ctk.CTkEntry(frame, placeholder_text="输入框示例").pack(pady=10)
        ctk.CTkButton(frame, text="示例按钮").pack(pady=10)
        ctk.CTkCheckBox(frame, text= "复选框示例").pack(pady=10)
        ctk.CTkSwitch(frame, text="开关示例").pack(pady=10)
    
    deftoggle_theme(self):
        """切换主题"""
        if self.current_theme == "dark":
            ctk.set_appearance_mode("light")
            self.current_theme = "light"
            self.theme_btn.configure(text="切换到深色模式")
        else:
            ctk.set_appearance_mode("dark")
            self.current_theme = "dark"
            self.theme_btn.configure(text="切换到浅色模式")
    
    defrun(self):
        self.app.mainloop()

# 运行应用
if __name__ == "__main__":
    app = ThemeSwitcherApp()
    app.run()

技巧2:响应式布局(自适应窗口大小)

上下滑动查看更多源码

import customtkinter as ctk

classResponsiveApp:
    def__init__(self):
        self.app = ctk.CTk()
        self.app.title("响应式布局示例")
        self.app.geometry("800x600")
        
        # 绑定窗口大小变化事件
        self.app.bind("", self.on_window_resize)
        
        self.create_responsive_layout()
    
    defcreate_responsive_layout(self):
        """创建响应式布局"""
        # 使用网格布局,更灵活
        self.app.grid_rowconfigure(0, weight=1)  # 顶部区域
        self.app.grid_rowconfigure(1, weight=3)  # 主要内容区域
        self.app.grid_rowconfigure(2, weight=1)  # 底部区域
        self.app.grid_columnconfigure(0, weight=1 )
        self.app.grid_columnconfigure(1, weight=3)
        self.app.grid_columnconfigure(2, weight=1)
        
        # 1. 顶部导航栏
        top_frame = ctk.CTkFrame(self.app, height=60, corner_radius=0)
        top_frame.grid(row=0, column=0, columnspan=3, sticky="nsew")
        top_frame.grid_propagate(False)  # 固定高度
        
        # 导航按钮
        nav_buttons = ["首页""产品""关于""联系"]
        for i, text in enumerate(nav_buttons):
            btn = ctk.CTkButton(
                top_frame,
                text=text,
                width=100,
                height=40,
                fg_color="transparent",
                border_width=1
            )
            btn.pack(side="left", padx=10, pady=10)
        
        # 2. 侧边栏(小屏幕时会自动调整)
        sidebar = ctk.CTkFrame(self.app, width=200, corner_radius=0)
        sidebar.grid(row=1, column=0, sticky="nsew", padx=(05))
        sidebar.grid_propagate(False)
        
        # 侧边栏内容
        ctk.CTkLabel(sidebar, text="导航菜单", font=("Arial"16"bold")).pack(pady=20)
        for i in range(5):
            btn = ctk.CTkButton(
                sidebar,
                text=f"菜单项 {i+1}",
                anchor="w",
                height=40,
                fg_color="transparent",
                text_color=("gray10""gray90")
            )
            btn.pack(fill="x", padx=10, pady=5)
        
        # 3. 主内容区
        main_content = ctk.CTkFrame(self.app)
        main_content.grid(row=1, column=1, sticky="nsew", padx=5, pady=5)
        
        # 内容标题
        ctk.CTkLabel(
            main_content,
            text="主要内容区域",
            font=( "Arial"20"bold")
        ).pack(pady=20)
        
        # 响应式文本 - 根据窗口大小调整
        self.responsive_label = ctk.CTkLabel(
            main_content,
            text="调整窗口大小看看效果...",
            font=("Arial"14),
            wraplength=400# 初始换行宽度
        )
        self.responsive_label.pack(pady=20, padx=20)
        
        # 4. 右侧边栏
        right_sidebar = ctk.CTkFrame(self.app, width=150)
        right_sidebar.grid(row=1, column=2, sticky="nsew", padx=(50))
        right_sidebar.grid_propagate(False)
        
        ctk.CTkLabel(right_sidebar, text="工具", font=("Arial"14)).pack(pady=20)
        ctk.CTkButton(right_sidebar, text="工具1").pack(pady=5)
        ctk.CTkButton(right_sidebar, text="工具2").pack(pady=5)
        
        # 5. 底部状态栏
        bottom_frame = ctk.CTkFrame(self.app, height=40, corner_radius=0)
        bottom_frame.grid(row=2, column=0, columnspan=3, sticky="nsew")
        bottom_frame.grid_propagate(False)
        
        # 状态信息
        self.status_label = ctk.CTkLabel(
            bottom_frame,
            text="就绪 | 窗口大小: 800x600"
        )
        self.status_label.pack(side="left", padx=20)
    
    defon_window_resize(self, event):
        """窗口大小变化时的处理"""
        if event.widget == self.app:
            width = event.width
            height = event.height
            
            # 更新状态栏信息
            self.status_label.configure(text=f"就绪 | 窗口大小: {width}x{height}")
            
            # 调整响应式标签的换行宽度
            new_wrap_length = max(200, width // 3)
            self.responsive_label.configure(wraplength=new_wrap_length)
    
    defrun(self):
        self.app.mainloop()

# 运行应用
if __name__ == "__main__":
    app = ResponsiveApp()
    app.run()

技巧3:自定义复合组件(提高代码复用)

上下滑动查看更多源码

import customtkinter as ctk

classModernComponents:
    """现代化组件集合"""
    
    @staticmethod
    defcreate_card(master, title, content, width=300, height=200):
        """创建卡片式组件"""
        card = ctk.CTkFrame(
            master,
            width=width,
            height=height,
            corner_radius=15,
            border_width=1,
            border_color="#E0E0E0"
        )
        card.grid_propagate(False)
        
        # 卡片标题
        title_label = ctk.CTkLabel(
            card,
            text=title,
            font=("Arial"16"bold"),
            anchor="w"
        )
        title_label.grid(row=0, column=0, padx=20, pady=(2010), sticky="w")
        
        # 卡片内容
        content_label = ctk.CTkLabel(
            card,
            text=content,
            font=("Arial"12),
            wraplength=width-40,
            justify="left"
        )
        content_label.grid(row=1, column=0, padx=20, pady=10, sticky="w")
        
        # 卡片底部操作按钮
        button_frame = ctk.CTkFrame(card, fg_color="transparent")
        button_frame.grid(row=2, column=0, padx=20, pady=(1020), sticky="e")
        
        ctk.CTkButton(
            button_frame,
            text="详情",
            width=80,
            height=30
        ).pack(side="left", padx=5)
        
        ctk.CTkButton(
            button_frame,
            text="操作",
            width=80,
            height=30,
            fg_color="#4CAF50",
            hover_color="#45A049"
        ).pack(side="left", padx=5)
        
        return card
    
    @staticmethod
    defcreate_metric_display(master, title, value, unit="", trend="up"):
        """创建指标显示组件"""
        frame = ctk.CTkFrame(master, height=120, width=180)
        frame.grid_propagate(False)
        
        # 指标标题
        ctk.CTkLabel(
            frame,
            text=title,
            font=("Arial"12),
            text_color="gray"
        ).grid(row=0, column=0, padx=20, pady=(205), sticky="w")
        
        # 指标值
        value_label = ctk.CTkLabel(
            frame,
            text=f"{value}{unit}",
            font=("Arial"24"bold")
        )
        value_label.grid(row=1, column=0, padx=20, sticky="w")
        
        # 趋势指示器
        trend_color = "#4CAF50"if trend == "up"else"#F44336"
        trend_symbol = "↗"if trend == "up"else"↘"
        
        trend_label = ctk.CTkLabel(
            frame,
            text=f"{trend_symbol} 12.5%",
            text_color=trend_color,
            font=("Arial"12)
        )
        trend_label.grid(row=1, column=1, padx=(020), sticky="e")
        
        return frame

# 使用自定义组件
app = ctk.CTk()
app.geometry("900x600")
app.title("自定义复合组件示例")

# 使用卡片组件
card1 = ModernComponents.create_card(
    app,
    "项目进度",
    "当前项目已完成80%的主要功能开发,测试阶段进展顺利。",
    width=400,
    height=180
)
card1.grid(row=0, column=0, padx=20, pady=20, sticky="nw")

card2 = ModernComponents.create_card(
    app,
    "团队协作",
    "本周团队完成了3个重要功能的开发,代码审查通过率100%。",
    width=400,
    height=180
)
card2.grid(row=0, column=1, padx=20, pady=20, sticky="nw")

# 使用指标显示组件
metrics_frame = ctk.CTkFrame(app)
metrics_frame.grid(row=1, column=0, columnspan=2, padx=20, pady=20, sticky="ew")

# 创建多个指标
metrics = [
    ("用户增长""1,234""人""up"),
    ("收入""¥56,789""""up"),
    ("满意度""94.5""%""up"),
    ("问题数""12""个""down")
]

for i, (title, value, unit, trend) in enumerate(metrics):
    metric = ModernComponents.create_metric_display(
        metrics_frame,
        title,
        value,
        unit,
        trend
    )
    metric.grid(row=0, column=i, padx=10, pady=10)

app.mainloop()

常见挑战及故障排除技巧

在使用 CustomTkinter 时,开发人员可能会遇到一些常见问题,例如布局问题、事件处理复杂性或兼容性问题。为了解决这些问题,请考虑以下故障排除技巧:

  1. 打印调试:策略性地使用打印语句来跟踪执行流程并识别潜在问题。
  2. 异常处理:使用 try-except 块包裹代码的关键部分,以捕获和记录异常,从而更好地理解错误。
  3. 日志记录:实现日志记录机制,以记录小部件执行期间的事件、操作和错误。
  4. 逐步执行:将复杂的方法分解成更小的函数,并逐步执行它们,以找出问题的根源。
  5. 社区和文档:请参阅 CustomTkinter 文档和社区论坛,了解常见问题和解决方案。

通过运用这些调试技术,开发人员可以高效地识别和解决 CustomTkinter 小部件中的问题,从而确保流畅的开发体验。

将 CustomTkinter 与其他库集成

CustomTkinter 可以与其他 Python 库和框架集成,以增强其功能。例如,它可以与 Matplotlib 等数据可视化库或 Plotly 的交互式元素结合使用,从而创建具有现代化 UI 组件的丰富数据驱动型应用程序。

真实案例

多个实际应用和项目已有效地利用 CustomTkinter 创建了现代化且美观的用户界面,用于各种用途。这些应用涵盖数据可视化、科学计算以及企业内部工具等多个行业。

用CustomTkinter打造个人任务管理器

上下滑动查看更多源码

import customtkinter as ctk
import json
import os
from datetime import datetime

classTaskManagerApp:
    def__init__(self):
        self.app = ctk.CTk()
        self.app.title("个人任务管理器")
        self.app.geometry("1000x700")
        
        # 设置主题
        ctk.set_appearance_mode("dark")
        ctk.set_default_color_theme("green")
        
        # 任务数据
        self.tasks = []
        self.data_file = "tasks.json"
        
        # 加载已有任务
        self.load_tasks()
        
        # 创建界面
        self.create_ui()
    
    defcreate_ui(self):
        """创建用户界面"""
        # 主布局:左右分栏
        self.app.grid_columnconfigure(0, weight=1)
        self.app.grid_columnconfigure(1, weight=3)
        self.app.grid_rowconfigure( 0, weight=1)
        
        # 左侧:任务添加面板
        left_panel = ctk.CTkFrame(self.app)
        left_panel.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
        
        # 任务添加表单
        ctk.CTkLabel(
            left_panel,
            text="添加新任务",
            font=("Arial"18"bold")
        ).pack(pady=20)
        
        # 任务标题
        ctk.CTkLabel(left_panel, text="任务标题:").pack(pady=(05))
        self.title_entry = ctk.CTkEntry(left_panel, width=200)
        self.title_entry.pack(pady=(015))
        
        # 任务描述
        ctk.CTkLabel(left_panel, text="任务描述:").pack(pady=(05))
        self.desc_text = ctk.CTkTextbox(left_panel, width=200, height=100)
        self.desc_text.pack(pady=(015))
        
        # 优先级
        ctk.CTkLabel(left_panel, text="优先级:").pack(pady=(05))
        self.priority_var = ctk.StringVar(value="中")
        priority_frame = ctk.CTkFrame(left_panel, fg_color="transparent")
        priority_frame.pack(pady=(015))
        
        priorities = ["高""中""低"]
        for priority in priorities:
            rb = ctk.CTkRadioButton(
                priority_frame,
                text=priority,
                variable=self.priority_var,
                value=priority
            )
            rb.pack(side="left", padx=10)
        
        # 截止日期
        ctk.CTkLabel(left_panel, text="截止日期:").pack(pady=(05))
        self.date_entry = ctk.CTkEntry(
            left_panel,
            width=200,
            placeholder_text="YYYY-MM-DD"
        )
        self.date_entry.pack(pady=(020))
        
        # 添加按钮
        add_button = ctk.CTkButton(
            left_panel,
            text="添加任务",
            command=self.add_task,
            height=40,
            font=("Arial"14)
        )
        add_button.pack(pady=10)
        
        # 右侧:任务列表
        right_panel = ctk.CTkFrame(self.app)
        right_panel.grid(row=0, column=1, sticky="nsew", padx=10, pady=10)
        
        # 任务列表标题
        ctk.CTkLabel(
            right_panel,
            text="任务列表",
            font=("Arial"18"bold")
        ).pack(pady=20)
        
        # 搜索框
        search_frame = ctk.CTkFrame(right_panel, fg_color="transparent")
        search_frame.pack(fill="x", padx=20, pady=(020))
        
        ctk.CTkLabel(search_frame, text="搜索:").pack(side="left", padx=(010))
        self.search_entry = ctk.CTkEntry(search_frame, width=200)
        self.search_entry.pack(side="left")
        self.search_entry.bind("", self.filter_tasks)
        
        # 任务列表容器
        self.tasks_frame = ctk.CTkScrollableFrame(right_panel)
        self.tasks_frame.pack(fill="both", expand=True, padx=20, pady=(020))
        
        # 刷新任务列表
        self.refresh_task_list()
    
    defadd_task(self):
        """添加新任务"""
        title = self.title_entry.get().strip()
        description = self.desc_text.get("1.0""end").strip()
        priority = self.priority_var.get()
        due_date = self.date_entry.get().strip()
        
        ifnot title:
            self.show_message("错误""请输入任务标题")
            return
        
        # 创建任务对象
        task = {
            "id": len(self.tasks) + 1,
            "title": title,
            "description": description,
            "priority": priority,
            "due_date": due_date,
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "completed"False
        }
        
        self.tasks.append(task)
        self.save_tasks()
        self.refresh_task_list()
        
        # 清空表单
        self.title_entry.delete(0"end")
        self.desc_text.delete("1.0""end")
        self.date_entry.delete(0"end")
        
        self.show_message("成功""任务添加成功!")
    
    defrefresh_task_list(self):
        """刷新任务列表显示"""
        # 清除现有任务显示
        for widget in self.tasks_frame.winfo_children():
            widget.destroy()
        
        # 显示每个任务
        for task in self.tasks:
            self.create_task_widget(task)
    
    defcreate_task_widget(self, task):
        """创建单个任务的显示组件"""
        task_frame = ctk.CTkFrame(self.tasks_frame)
        task_frame.pack(fill="x", pady=5, padx=5)
        
        # 任务完成状态
        completed_var = ctk.BooleanVar(value=task["completed"])
        
        deftoggle_complete():
            task["completed"] = completed_var.get()
            self.save_tasks()
            self.refresh_task_list()
        
        checkbox = ctk.CTkCheckBox(
            task_frame,
            text="",
            variable=completed_var,
            command=toggle_complete,
            width=20
        )
        checkbox.grid(row=0, column=0, padx=10, pady=10, sticky="w")
        
        # 任务信息
        info_frame = ctk.CTkFrame(task_frame, fg_color="transparent")
        info_frame.grid(row=0, column=1, padx=10, pady=10, sticky="w")
        
        # 优先级颜色
        priority_colors = {"高""#FF4444""中""#FFAA44""低""#44AA44"}
        priority_color = priority_colors.get(task["priority"], "#666666")
        
        # 任务标题(带删除线如果已完成)
        title_font = ("Arial"14"bold")
        if task["completed"]:
            title_font = ("Arial"14"bold""overstrike")
        
        title_label = ctk.CTkLabel(
            info_frame,
            text=task["title"],
            font=title_font
        )
        title_label.grid(row=0, column=0, sticky="w")
        
        # 优先级标签
        priority_label = ctk.CTkLabel(
            info_frame,
            text=task["priority"],
            text_color=priority_color,
            font=("Arial"10"bold")
        )
        priority_label.grid(row=0, column=1, padx=10, sticky="w")
        
        # 截止日期
        if task["due_date"]:
            date_label = ctk.CTkLabel(
                info_frame,
                text=f"截止: {task['due_date']}",
                text_color="#888888",
                font=("Arial"10)
            )
            date_label.grid(row=1, column=0, columnspan=2, sticky="w", pady=(20))
        
        # 删除按钮
        delete_btn = ctk.CTkButton(
            task_frame,
            text="删除",
            width=60,
            height=30,
            fg_color="#FF4444",
            hover_color="#CC0000",
            command=lambda t=task: self.delete_task(t["id"])
        )
        delete_btn.grid(row=0, column=2, padx=10, sticky="e")
    
    defdelete_task(self, task_id):
        """删除任务"""
        self.tasks = [t for t in self.tasks if t["id"] != task_id]
        self.save_tasks()
        self.refresh_task_list()
    
    deffilter_tasks(self, event=None):
        """过滤任务列表"""
        search_text = self.search_entry.get().lower()
        
        for widget in self.tasks_frame.winfo_children():
            task_frame = widget
            
            # 获取任务标题(从标签中提取)
            for child in task_frame.winfo_children():
                if isinstance(child, ctk.CTkFrame):
                    for grandchild  in child.winfo_children():
                        if isinstance(grandchild, ctk.CTkLabel) and grandchild.cget("font")[2] == "bold":
                            title = grandchild.cget("text").lower()
                            if search_text in title:
                                task_frame.pack(fill="x", pady=5, padx=5)
                                break
                    else:
                        continue
                    break
            else:
                task_frame.pack_forget()
    
    defshow_message(self, title, message):
        """显示消息对话框"""
        dialog = ctk.CTkToplevel(self.app)
        dialog.title(title)
        dialog.geometry("300x150")
        
        # 居中显示
        dialog.transient(self.app)
        dialog.grab_set()
        
        ctk.CTkLabel(
            dialog,
            text=message,
            font=("Arial"14)
        ).pack(expand=True, pady=20)
        
        ctk.CTkButton(
            dialog,
            text="确定",
            command=dialog.destroy
        ).pack(pady=10)
    
    defload_tasks(self):
        """从文件加载任务"""
        if os.path.exists(self.data_file):
            try:
                with open(self.data_file, "r", encoding="utf-8"as f:
                    self.tasks = json.load(f)
            except:
                self.tasks = []
    
    defsave_tasks(self):
        """保存任务到文件"""
        with open(self.data_file, "w", encoding="utf-8"as f:
            json.dump(self.tasks, f, ensure_ascii=False, indent=2)
    
    defrun(self):
        self.app.mainloop()

# 启动应用
if __name__ == "__main__":
    app = TaskManagerApp()
    app.run()

这个任务管理器展示了CustomTkinter的 强大功能

  1. 现代化的深色主题,保护眼睛
  2. 响应式布局,自动适应窗口大小
  3. 丰富的组件:滚动区域、对话框、复选框等
  4. 数据持久化,保存任务到本地文件
  5. 交互体验:任务完成状态、搜索过滤、删除确认

性能考量

在使用 CustomTkinter 开发复杂的 GUI 应用程序时,必须考虑性能优化,例如高效的布局管理、资源处理和事件处理。通过遵循最佳实践并优化自定义组件,开发人员可以确保在各种应用场景下都能流畅运行。

使用自定义 Tkinter 而非标准 Tkinter 的优势

  1. 广泛的自定义:CustomTkinter 允许开发人员根据特定的设计要求定制小部件,与标准 Tkinter 小部件相比,提供了更高的灵活性。
  2. 模块化重用性:借助 CustomTkinter,您可以将自定义小部件封装到模块化组件中,从而提高不同项目之间的代码重用性。
  3. 简化样式:CustomTkinter 中的主题简化了样式设置过程,使整个应用程序的外观保持一致且美观。
  4. 增强的事件处理:CustomTkinter 提供了对事件处理的更多控制,允许开发人员自定义和扩展小部件的默认行为。
  5. 易于集成:CustomTkinter 与 Tkinter 无缝集成,在保持兼容性的同时提供高级自定义功能。

与其他 Python GUI 库相比的优势

  1. 现代外观和感觉:与标准 Tkinter 相比,它提供了更时尚、更现代的外观,对于想要更具视觉吸引力的产品的用户来说,这是一个不错的选择。
  2. Tkinter 的简洁性:CustomTkinter 保持了 Tkinter 的简洁语法,因此对于熟悉 Tkinter 但寻求更美观界面的用户来说,这是一个合适的选择。
  3. 额外的 UI 元素:它提供了额外的 UI 元素,例如 CTkButton,可以通过边框和圆角等功能进行自定义,从而在 UI 设计中提供更大的灵活性。
  4. 浅色和深色主题支持:CustomTkinter 同时支持浅色和深色主题,从而可以更好地自定义用户界面。

然而,与其他成熟的 GUI 框架相比,其潜在的缺点(例如社区支持和资源有限)也需要考虑。

特性
CustomTkinter
PyQt/PySide
Kivy
传统Tkinter
学习曲线
⭐⭐⭐⭐⭐(极易上手)
⭐⭐(较陡峭)
⭐⭐⭐(中等)
⭐⭐⭐⭐⭐(极易上手)
界面美观度
⭐⭐⭐⭐⭐(现代化)
⭐⭐⭐⭐⭐(非常美观)
⭐⭐⭐⭐(现代化)
⭐⭐(较老旧)
开发速度
⭐⭐⭐⭐⭐(快速)
⭐⭐⭐(中等)
⭐⭐⭐(中等)
⭐⭐⭐⭐(快速)
功能丰富度
⭐⭐⭐(基础功能齐全)
⭐⭐⭐⭐⭐(极其丰富)
⭐⭐⭐⭐(丰富)
⭐⭐⭐(基础功能)
部署大小
⭐⭐⭐⭐⭐(很小)
⭐⭐(较大)
⭐⭐⭐(中等)
⭐⭐⭐⭐⭐(很小)
社区支持
⭐⭐⭐(增长中)
⭐⭐⭐⭐⭐(强大)
⭐⭐⭐⭐(活跃)
⭐⭐⭐⭐⭐(强大)

选择CustomTkinter的三大理由:

  1. 平滑迁移:如果你已经熟悉Tkinter,迁移到CustomTkinter几乎零成本
  2. 快速交付:对于需要快速开发并交付的內部工具或中小型项目,CustomTkinter是完美选择
  3. 现代外观:无需深入学习复杂框架,就能获得现代化界面

CustomTkinter 与 PyQt

表现:

  • CustomTkinter:轻量级且与 Tkinter 无缝集成,可为各种应用提供良好的性能。
  • PyQt:功能丰富,但体积可能较大,可能导致更高的资源消耗。

特征:

  • CustomTkinter:提供丰富的自定义选项,打造专属外观和风格。
  • PyQt:提供多种功能,包括用于 UI 设计的图形设计工具。

学习曲线:

  • CustomTkinter:继承了 Tkinter 的简洁性,使熟悉 Tkinter 的开发人员能够轻松上手。
  • PyQt:由于其丰富的功能集和面向对象的方法,学习曲线较为陡峭。

CustomTkinter 与 Kivy 的比较

表现:

  • CustomTkinter:专注于桌面应用程序,并在标准 GUI 场景下保持良好的性能。
  • Kivy:主要为移动应用程序设计,性能表现可能有所不同。

特征:

  • CustomTkinter:专门用于桌面应用程序的定制和扩展。
  • Kivy:以其跨平台功能而闻名,尤其是在移动和触控应用程序方面。

学习曲线:

  • CustomTkinter:继承了 Tkinter 的简洁性,使 Tkinter 用户能够轻松上手。
  • Kivy:可能存在一定的学习曲线,特别是对于不熟悉其独特结构的开发者而言。

CustomTkinter 的局限性和缺点

  1. 对 Tkinter 的依赖:CustomTkinter 构建于 Tkinter 之上,虽然这确保了兼容性,但也意味着继承了 Tkinter 中存在的任何限制。
  2. 社区规模:虽然 CustomTkinter 社区正在发展,但与更成熟的库相比,其规模可能较小,这可能导致资源和社区支持较少。
  3. 功能完整性:PyQt 或 Kivy 中的一些高级功能在 CustomTkinter 中可能不容易获得或未完全开发。
  4. 学习资源:虽然有文档、教程和示例,但可用的资源可能不如主流库那样丰富。

写在最后

通过今天的分享,相信你已经看到了CustomTkinter的强大之处。让我总结一下它的核心优势:

  • 上手极其简单:如果你会Tkinter,就会CustomTkinter,学习成本几乎为零
  • 界面现代化:深色模式、圆角设计、平滑动画,让应用瞬间提升档次
  • 开发速度快:无需复杂配置,几行代码就能创建专业界面
  • 完美兼容:可以和传统Tkinter组件混合使用,渐进式迁移
  • 响应式设计:内置对高DPI显示器的支持,适配各种屏幕

Python CustomTkinter 为开发者提供了一个宝贵的机会,让我们能够在 Python 应用程序中创建美观且功能丰富的用户界面。通过了解其功能、最佳实践和集成潜力,开发者可以利用 CustomTkinter 在各个领域打造引人入胜的应用程序。

Python CustomTkinter 通过提供前所未有的自定义功能,显著提升了 GUI 开发水平。开发者可以创建视觉效果惊艳且功能强大的应用程序,同时保持 Tkinter 的简洁易用性。

适用场景推荐:

  1. 内部工具开发:快速为团队打造现代化管理工具
  2. 原型验证:在投入大量前端开发前,先用Python验证产品概念
  3. 数据科学展示:为数据分析结果创建美观的展示界面
  4. 教育工具:开发教学演示程序,界面友好吸引学生
  5. 个人项目:为自己打造高效的生产力工具

🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉 PythonMySQL数据分析数据可视化机器学习与数据挖掘 爬虫 等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/191319