跳转至

组件总览

所有组件都可以从包根直接导入:

import tkflu
# 或者
from tkflu import FluWindow, FluButton, FluFrame

长什么样

图鉴里的每一格都是从真实运行的组件上截下来的(不是设计稿):

组件图鉴(浅色)

浅色主题下的组件图鉴

组件图鉴(深色)

同一批组件切到深色主题:绘制层不用改,只是配色字典变了

一览表

组件 用途 关键参数
FluWindow 主窗口(应用根窗口) mode
FluToplevel 子窗口 mode
FluFrame 圆角面板 / 容器 width height mode style
FluLabel 文本标签 text width height font
FluButton 按钮 text style state command
FluToggleButton 开关 text command(读 dcget("checked"))
FluCheckBox 复选框(含不确定态) text checked three_state command
FluRadioBox 单选框 text value variable / group
FluBadge 徽标 / 胶囊标签 text width style
FluEntry 单行输入框 width textvariable state
FluText 多行文本框 width height state
FluSlider 滑块 value min max orient tick changed
FluScrollBar 滚动条 command orient state
FluListBox 列表 items selectmode command on_select
FluLiteNav 轻量导航栏 items orient selected command
FluImage 图片 image(路径 / PhotoImage / PIL.Image)
FluMenu 下拉菜单 add_command / add_cascade
FluMenuBar 菜单栏 add_command / add_cascade
FluPopupMenu 弹出菜单 —
FluPopupWindow 通用弹出窗口 —
FluToolTip 悬浮提示 通过组件的 .tooltip() 挂载
FluThemeManager 主题管理 mode / toggle

选择类控件怎么选

想要的效果 用哪个
开关式的"开 / 关" FluToggleButton
复选(可多选、可不确定) FluCheckBox
一组里只能选一个 FluRadioBox
一组里选一个、但要滚动 / 分栏 FluListBox(selectmode="single")
页面/区块之间切换 FluLiteNav

复选框与单选框

两者都是"指示器 + 标签"的组合,键盘都能用 Tab 聚焦、空格 触发。

import tkinter as tk
import tkflu

root = tkflu.FluWindow()
root.geometry("360x260")

# 复选框:checked 允许 True / False / None
box = tkflu.FluCheckBox(root, text="启用动画", checked=True)
box.pack(anchor="w", padx=14, pady=6)

three = tkflu.FluCheckBox(root, text="三态(不确定)", three_state=True, checked=None)
three.pack(anchor="w", padx=14, pady=6)

# 单选框:同一个 variable 自动互斥
plan = tk.StringVar(master=root, value="b")
for key, title in (("a", "方案 A"), ("b", "方案 B"), ("c", "方案 C")):
    tkflu.FluRadioBox(root, text=title, variable=plan, value=key).pack(
        anchor="w", padx=14, pady=4
    )

def on_change():
    print("动画:", box.dcget("checked"), " 方案:", plan.get())

box.dconfigure(command=on_change)
root.mainloop()

不想自己建变量时,可以给一组单选框起同一个组名:

tkflu.FluRadioBox(root, text="甲", group="plan", value="a")
tkflu.FluRadioBox(root, text="乙", group="plan", value="b")

group 会在同一个窗口内共享一个变量,窗口销毁时自动回收。

列表

FluListBox 自己绘制条目,只画可见的那几行(虚拟滚动), 所以放几千条也不会卡。选中行左侧有一条强调色指示条, 右侧的滚动条可以拖动、也可以滚轮滚。

import tkflu

root = tkflu.FluWindow()
root.geometry("360x320")

box = tkflu.FluListBox(
    root,
    width=300,
    height=180,
    items=[f"第 {i} 行" for i in range(1, 101)],
    selectmode="extended",          # single / multiple / extended
    command=lambda index, item: print("激活", index, item),
    on_select=lambda indices, items: print("选中", indices),
)
box.pack(padx=16, pady=16)

box.insert("end", "新加的")
box.select(2)
box.see(50)
print(box.selection(), box.get(2))
root.mainloop()
方法 说明
insert(index, item) / append(item) 插入 / 追加条目
delete_item(index) / clear() 删除一条 / 清空
get(index) / index(item) 取条目 / 取下标
select deselect select_all clear_selection 改选择
selection() / curselection() 取当前选中的下标元组
see(index) / yview(...) 滚动
activate(index) 触发 command

条目删除叫 delete_item,不叫 delete

控件本身是一个 tkinter.Canvas,delete 是"删除画布元素"的意思 (重绘时第一件事就是 self.delete("all"))。两者同名会递归调用自己。

导航栏

FluLiteNav 是一排可点条目 + 一个选中项:竖排时指示条在左,横排时在下方。

import tkflu

root = tkflu.FluWindow()
root.geometry("420x160")

nav = tkflu.FluLiteNav(
    root,
    items=[
        ("🏠", "首页"),
        ("🔍", "搜索"),
        {"label": "设置", "icon": "⚙", "key": "settings"},
    ],
    orient="horizontal",     # 或 "vertical"
    style="card",            # standard = 透明底
    selected="settings",
)
nav.pack(padx=16, pady=16)

nav.dconfigure(command=lambda index, item: print("切到", item["key"]))
nav.add_item("关于", icon="ℹ", key="about")
root.mainloop()

条目可以是 "标签"、("图标", "标签") 或字典 (label / icon / key / enabled / command)。

最小示例

import tkflu

root = tkflu.FluWindow(mode="light")
root.geometry("360x260")

frame = tkflu.FluFrame(root, width=320, height=220)
frame.pack(fill="both", expand=True, padx=15, pady=15)

tkflu.FluLabel(frame, text="你好,tkfluent").pack(anchor="w", padx=10, pady=(10, 4))

tkflu.FluButton(frame, text="点我", command=lambda: print("clicked")).pack(
    fill="x", padx=10, pady=4
)

entry = tkflu.FluEntry(frame, width=280)
entry.pack(fill="x", padx=10, pady=4)

root.mainloop()

按钮的三种样式

FluButton 的样式与状态组合起来共 12 种外观(mode 再翻一倍)。下图是 同一批真实按钮分别被设成 rest / hover / pressed / disabled 后重绘的结果:

按钮状态矩阵

4 状态 × 3 样式,浅色与深色各一组(放大 2 倍)。悬停与按压只是透明度不同,这是 Fluent 的设计
import tkflu

root = tkflu.FluWindow()

tkflu.FluButton(root, text="standard").pack(padx=10, pady=4)
tkflu.FluButton(root, text="accent", style="accent").pack(padx=10, pady=4)
tkflu.FluButton(root, text="menu", style="menu").pack(padx=10, pady=4)
tkflu.FluButton(root, text="disabled", state="disabled").pack(padx=10, pady=4)

root.mainloop()

开关与状态读取

FluToggleButton 的选中状态存在组件的 attributes 里,用 dcget 读取:

toggle = tkflu.FluToggleButton(root, text="启用")

def on_toggle():
    print("当前状态:", toggle.dcget("checked"))

toggle.dconfigure(command=on_toggle)

同样的 dcget / dconfigure 也适用于其他组件(它们是 tkdeft.object.DObject 提供的统一配置接口):

button.dconfigure(text="新的文字", state="disabled")
print(button.dcget("state"))     # 'disabled'

挂提示

任何继承 FluToolTipBase 的组件都能挂一个 Fluent 风格的提示:

label = tkflu.FluLabel(root, text="把鼠标放上来")
label.tooltip(text="我是提示")

标签的宽度自适应

FluLabel 是一块固定尺寸的画布,文本在中间居中绘制。文本一旦比画布宽, 左右两侧都会被裁掉。

从 0.2.0 起,不传 width 时标签会按文本自动撑开(只增不减, 避免文字变化时抖动):

# 自动宽度:文字多长,标签就多宽,不会被裁
tkflu.FluLabel(root, text="FluLabel(悬停看提示)")

# 显式指定宽度:行为与旧版一致,超出仍然会裁
tkflu.FluLabel(root, text="...", width=120)

需要动态改文字时同理,改完调一次 _draw() 让它重新量宽:

label.dconfigure(text="一段更长的文字")
label._draw()

容器怎么用

FluFrame 内部是"画布 + 子 Frame"的结构,但它把 pack / grid / place 都代理给了内部画布,所以你可以像用普通容器一样用它:

frame = tkflu.FluFrame(root, width=300, height=200)
frame.pack(padx=10, pady=10)

tkflu.FluButton(frame, text="在面板里").pack(padx=8, pady=8)

想直接看效果

python -m tkflu

会打开一个把所有组件摆在一起的画廊,详见 运行演示。