Textual 边框副标题样式指南:border-subtitle-style 的完整用法与源码解析
【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textual
border-subtitle-style是 Textual 中用于设置控件边框副标题(subtitle)文字样式的 CSS 属性,它决定了边框副标题是加粗、斜体、下划线还是其他视觉形态。本文以该样式属性为核心,结合 Textual 源码与官方示例,系统讲解其语法、取值、CSS 与 Python 两种设置方式,以及与之配套的边框标题/副标题样式体系,帮助你在终端 UI 开发中精确控制边框文字外观。
属性概述
border-subtitle-style设置的是 border_subtitle(即边框副标题文本)的文字样式。所谓边框副标题,是指显示在控件边框底边上的文本,与显示在顶边的border_title(边框标题)相对应。边框副标题是 Textual 边框体系的一部分,需要控件设置了border样式后才会显示出来。
在 Textual 的样式体系中,该属性的底层实现位于 src/textual/css/styles.py:
border_subtitle_style = StyleFlagsProperty()它由StyleFlagsProperty这一描述符(descriptor)管理,存储的是一个 Rich 的Style对象(即rich.style.Style),而不是简单的字符串。
语法
border-subtitle-style的取值是一个<text-style>类型:
border-subtitle-style: <text-style>;在 CSS 规则中书写示例:
border-subtitle-style: bold underline;在 Python 中通过styles对象动态设置:
widget.styles.border_subtitle_style = "bold underline"需要注意,<text-style>是一个 CSS 类型,不要与设置控件内文本样式的text-styleCSS 规则混淆——后者作用于控件内部的文本,而前者只作用于边框副标题。
可选值
<text-style>可以是值none(表示纯文本、无任何样式),也可以是以下取值中任意以空格分隔的组合:
| 值 | 描述 |
|---|---|
bold | 加粗文本 |
italic | 斜体文本 |
reverse | 反显文本(前景色与背景色互换) |
strike | |
underline | 下划线文本 |
在 CSS 中既可单独指定一个值,也可组合多个值:
#label1 { /* 单独指定一个值 */ border-subtitle-style: strike; } #label2 { /* 组合多个值 */ border-subtitle-style: strike bold italic reverse; }Python 中的写法与此对应:
# 单独指定一个值 widget.styles.border_subtitle_style = "strike" # 组合多个值 widget.styles.border_subtitle_style = "strike bold italic reverse"源码层面的取值集合
从源码看,Textual 解析样式标记时实际接受的合法值比文档表格更丰富。在 src/textual/css/constants.py 中定义了完整的VALID_STYLE_FLAGS:
VALID_STYLE_FLAGS: Final = { "b", "blink", "bold", "dim", "i", "italic", "none", "not", "o", "overline", "reverse", "strike", "u", "underline", "uu", }也就是说,除表格中的五个值外,还支持blink(闪烁)、dim(弱化显示)、overline(上划线),以及b、i、u等短写形式(源自 Rich 的 StyleFlags)。但官方文档与 CSS 类型说明仍以bold、italic、reverse、strike、underline、none为推荐写法,组合时各项之间以空格分隔。
非法值的处理
在 CSS 解析阶段,_styles_builder.py的process_text_style方法会逐一校验每个 token 是否在VALID_STYLE_FLAGS中,非法值会触发样式解析错误(见 src/textual/css/_styles_builder.py):
def process_text_style(self, name: str, tokens: list[Token]) -> None: for token in tokens: value = token.value if value not in VALID_STYLE_FLAGS: self.error( # ... 报错并给出提示 ) style_definition = " ".join(token.value for token in tokens) self.styles._rules[name.replace("-", "_")] = style_definition有趣的是,border-subtitle-style并没有独立的解析函数,而是直接复用process_text_style(见 src/textual/css/_styles_builder.py):
process_border_title_style = process_text_style process_border_subtitle_style = process_text_style这说明 Textual 将link-style、text-style与边框标题/副标题的样式统一为同一套文本样式解析逻辑。
完整示例
官方文档中的示例位于 docs/examples/styles/border_title_colors.py 与 docs/examples/styles/border_title_colors.tcss,同时演示了边框标题与副标题的颜色、背景和文字样式定制。
border_title_colors.py内容如下:
from textual.app import App, ComposeResult from textual.widgets import Label class BorderTitleApp(App): CSS_PATH = "border_title_colors.tcss" def compose(self) -> ComposeResult: yield Label("Hello, World!") def on_mount(self) -> None: label = self.query_one(Label) label.border_title = "Textual Rocks" label.border_subtitle = "Textual Rocks" if __name__ == "__main__": app = BorderTitleApp() app.run()对应的border_title_colors.tcss:
Screen { align: center middle; } Label { padding: 4 8; border: heavy red; border-title-color: green; border-title-background: white; border-title-style: bold; border-subtitle-color: magenta; border-subtitle-background: yellow; border-subtitle-style: italic; }运行效果:屏幕中央的 Label 拥有红色粗边框,顶边标题 "Textual Rocks" 为白底绿字加粗,底边副标题同为 "Textual Rocks" 但为黄底品红字斜体。把 CSS 中的border-subtitle-style换成bold underline等组合值,即可直观看到副标题形态变化。
示例要点拆解
- 标题与副标题文本通过
label.border_title = "..."与label.border_subtitle = "..."在 Python 侧设置; - 颜色、背景与文字样式分别由
border-title-color/border-subtitle-color、border-title-background/border-subtitle-background、border-title-style/border-subtitle-style六条规则控制; border: heavy red声明了边框的绘制样式与颜色,是标题/副标题可见的前提。
Python 中的动态设置
widget.styles.border_subtitle_style返回的是一个Style对象,赋值时既可以传入字符串,也可以直接传入Style实例,还可以传None来清除已设置的规则。这一行为由StyleFlagsProperty描述符实现(见 src/textual/css/_style_properties.py):
class StyleFlagsProperty: """Descriptor for getting and set style flag properties (e.g. ``bold italic underline``).""" def __get__(self, obj, objtype=None) -> Style: return obj.get_rule(self.name, Style.null()) def __set__(self, obj, style_flags: Style | str | None) -> None: if style_flags is None: if obj.clear_rule(self.name): obj.refresh(children=True) elif isinstance(style_flags, Style): if obj.set_rule(self.name, style_flags): obj.refresh(children=True) else: # 将字符串按空格拆分并逐个校验后设置 ...由此可知:
- 设置
"bold underline"这类字符串时,内部会按空格拆分并校验每个标记,非法标记会抛出StyleValueError; - 传入
None会清除该样式规则,使副标题恢复默认的无样式状态; - 无论通过哪种方式修改,只要规则发生实际变化,控件都会触发
refresh重绘。
例如:
from rich.style import Style label = self.query_one(Label) label.styles.border_subtitle_style = "bold underline" # 字符串方式 label.styles.border_subtitle_style = Style(bold=True, italic=True) # Style 对象方式 label.styles.border_subtitle_style = None # 清除规则副标题样式的渲染链路
从样式设置到最终绘制,border-subtitle-style会经历一条完整的调用链:
- CSS 解析:
_styles_builder.py中的process_border_subtitle_style校验标记并写入样式规则; - 样式存储:
Styles.border_subtitle_style(src/textual/css/styles.py)以Style形式保存; - 渲染取值:在 src/textual/dom.py 中,DOM 节点获取边框副标题的渲染参数时,将样式转换为
VisualStyle:
return ( color, styles.border_subtitle_background, VisualStyle.from_rich_style(styles.border_subtitle_style), )- 样式序列化:
Styles.css导出时,会把该规则输出为subtitle-text-style声明(见 src/textual/css/styles.py):
if "border_subtitle_text_style" in rules: append_declaration("subtitle-text-style", str(self.border_subtitle_style))这条调用链印证了:border-subtitle-style与边框副标题的颜色、背景色共同构成副标题的完整外观,三者分别在渲染时被读取并合并绘制。
相关样式与配套体系
border-subtitle-style属于边框标题/副标题样式家族中的一员。完整的相关样式如下(见 docs/snippets/see_also_border.md):
border-title-align:设置边框标题(顶边)的对齐方式;border-title-color:设置边框标题的颜色;border-title-background:设置边框标题的背景色;border-title-style:设置边框标题的文字样式;border-subtitle-align:设置边框副标题(底边)的对齐方式;border-subtitle-color:设置边框副标题的颜色;border-subtitle-background:设置边框副标题的背景色;border-subtitle-style:设置边框副标题的文字样式(即本文)。
此外,border-title-style与border-subtitle-style在底层共用同一StyleFlagsProperty与同一解析函数,两者的取值、语法与动态设置方式完全一致,可相互参照。
小结
border-subtitle-style用<text-style>类型的值控制边框副标题文字形态,支持bold、italic、reverse、strike、underline、none及它们的空格分隔组合;- 既可以在
.tcss样式表中静态声明,也可以通过widget.styles.border_subtitle_style在 Python 中动态读写; - 底层由
StyleFlagsProperty管理,存储为 RichStyle,字符串赋值经VALID_STYLE_FLAGS校验,非法值直接报错; - 配合
border、border-subtitle-color、border-subtitle-background、border-subtitle-align等规则,可以完整定制边框副标题的显示效果。
如需查看该属性的实时渲染效果,可运行官方示例 docs/examples/styles/border_title_colors.py(需与同目录下的border_title_colors.tcss放在一起,并以该目录为工作目录执行)。
【免费下载链接】textualThe lean application framework for Python. Build sophisticated user interfaces with a simple Python API. Run your apps in the terminal and a web browser.项目地址: https://gitcode.com/gh_mirrors/te/textual
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考