You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tkinter Canvas上为文本添加多种字体样式

解决Tkinter Canvas中显示多格式文本的问题

Tkinter的Canvas组件本身不支持像Text那样的标签样式系统,要实现部分文本加粗/斜体,得手动解析带标签的输入文本,拆分不同样式的片段后逐个绘制。以下是实现方案:

核心思路

  • 解析输入的带标签文本(比如<b>、</b>、<i>、</i>),将文本拆分为「内容+对应字体样式」的片段列表
  • 清除Canvas上旧的文本元素,逐个绘制每个片段,根据样式设置字体
  • 保留原有的滚动逻辑,通过调整文本片段的Y坐标实现向上滚动

修改后的完整代码

import tkinter
import tkinter.scrolledtext
import re

def parse_formatted_text(text):
    # 解析<b>、</b>、<i>、</i>标签,返回(文本内容, 字体样式)的列表
    fragments = []
    current_style = "normal"
    # 使用正则拆分标签和文本
    parts = re.split(r'(<b>|</b>|<i>|</i>)', text)
    for part in parts:
        if part == '<b>':
            current_style = "bold"
        elif part == '</b>':
            current_style = "normal"
        elif part == '<i>':
            current_style = "italic"
        elif part == '</i>':
            current_style = "normal"
        elif part.strip():  # 跳过空内容
            fragments.append((part, current_style))
    return fragments

def draw_formatted_text(canvas, x, y, fragments, base_font="Arial 10", width=280):
    # 清除旧的文本元素
    for item in canvas.find_withtag("formatted_text"):
        canvas.delete(item)
    
    current_x = x
    current_y = y
    line_height = 14  # 根据字体调整行高
    max_width = width
    
    for text, style in fragments:
        # 根据样式设置字体
        if style == "bold":
            font = f"{base_font} bold"
        elif style == "italic":
            font = f"{base_font} italic"
        else:
            font = base_font
        
        # 处理文本换行(按宽度拆分)
        words = text.split()
        current_line = ""
        for word in words:
            test_line = f"{current_line} {word}".strip()
            # 计算当前测试行的宽度
            bbox = canvas.create_text((0,0), text=test_line, font=font, anchor=tkinter.SW)
            line_width = canvas.bbox(bbox)[2] - canvas.bbox(bbox)[0]
            canvas.delete(bbox)
            
            if line_width <= max_width or not current_line:
                current_line = test_line
            else:
                # 绘制当前行
                canvas.create_text((current_x, current_y), text=current_line, font=font, anchor=tkinter.SW, tag="formatted_text")
                current_y -= line_height
                current_line = word
        
        # 绘制剩余的当前行
        if current_line:
            canvas.create_text((current_x, current_y), text=current_line, font=font, anchor=tkinter.SW, tag="formatted_text")
            current_y -= line_height
    
    return current_y

def change_txtabs(event):
    abilities = txt_txtabs.get(1.0, tkinter.END).rstrip("\n")  # 去掉末尾换行
    fragments = parse_formatted_text(abilities)
    # 绘制格式化文本,锚点SW,从(12,432)开始
    draw_formatted_text(main_pct, 12, 432, fragments, width=280)

def scroll_text():
    # 实现文本向上滚动,每100ms移动1像素
    for item in main_pct.find_withtag("formatted_text"):
        x, y = main_pct.coords(item)
        main_pct.coords(item, x, y - 1)
    # 超出顶部的文本删除
    for item in main_pct.find_withtag("formatted_text"):
        bbox = main_pct.bbox(item)
        if bbox and bbox[3] < 0:  # 文本底部超出Canvas顶部
            main_pct.delete(item)
    window.after(100, scroll_text)

window = tkinter.Tk()
window.geometry('930x565')

txt_txtabs = tkinter.scrolledtext.ScrolledText(window, height=30, wrap='word', undo=True)
txt_txtabs.bind("<KeyPress>", change_txtabs)
txt_txtabs.bind("<KeyRelease>", change_txtabs)
txt_txtabs.place(x=10,y=10,width=300)

main_pct = tkinter.Canvas(bg='white', height=480, width=300)
main_pct.place(x=350,y=10)

# 启动滚动定时器
scroll_text()

window.mainloop()

关键部分说明

  1. 文本解析函数:parse_formatted_text用正则拆分标签和文本,跟踪当前样式,生成片段列表
  2. 绘制函数:draw_formatted_text负责清除旧元素,按宽度拆分文本换行,逐个绘制不同样式的片段,用formatted_text标签统一管理所有文本元素
  3. 滚动逻辑:scroll_text定时调整所有文本元素的Y坐标,超出Canvas顶部的元素自动删除,实现向上滚动效果

测试输入<b>This</b> word is <i>italic</i>.,Canvas会正确显示加粗的This和斜体的italic。

内容的提问来源于stack exchange,提问作者ToTaCe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 20:09:25