Textual ListView 指南:用 Python 构建可键盘导航的垂直列表界面
Textual ListView 指南用 Python 构建可键盘导航的垂直列表界面【免费下载链接】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导读ListView是 Textual 内置的垂直列表容器组件用于展示一组ListItem子项支持鼠标高亮与键盘导航是构建菜单、设置页、选择器、日志浏览等终端交互界面的基础构件。本文以官方文档 docs/widgets/list_view.md 为骨架结合 ListView 源码 与 ListView 测试用例完整讲解其特性、响应式属性、消息、按键绑定、动态增删项 API 与源码级工作原理读完即可在自己的 Textual 应用中落地使用。ListView 是什么ListView是一个可聚焦Focusable的容器组件以垂直方式展示若干个ListItem用户可以通过鼠标或键盘在其中移动高亮并选中条目。它自 0.6.0 版本起加入 Textual。从源码可以看出ListView 继承自VerticalScroll垂直滚动容器并以can_focusTrue, can_focus_childrenFalse声明列表本身可聚焦但其子项ListItem不可单独聚焦高亮操作统一由列表容器接管——这正是整表键盘导航体验的来源。可聚焦FocusableTab 键可以将焦点移到列表上从而启用键盘操作容器Container作为容器组件它可以承载多个ListItem子组件。它的默认 CSS见 源码 DEFAULT_CSS定义了完整的视觉状态列表背景使用$surface主题色直接子项ListItem高度自动、宽度占满width: 1fr、溢出隐藏鼠标悬停.-hovered与高亮.-highlight分别使用主题中的块级光标配色列表聚焦时叠加background-tint并切换高亮项为聚焦态光标配色$block-cursor-*系列。这些样式意味着你无需写任何 CSS 就能获得可用的默认外观同时也可以通过 CSS 覆盖。快速上手最小可运行示例官方文档提供了开箱即用的示例代码见 docs/examples/widgets/list_view.py样式表见 docs/examples/widgets/list_view.tcss。from textual.app import App, ComposeResult from textual.widgets import Footer, Label, ListItem, ListView class ListViewExample(App): CSS_PATH list_view.tcss def compose(self) - ComposeResult: yield ListView( ListItem(Label(One)), ListItem(Label(Two)), ListItem(Label(Three)), ) yield Footer() if __name__ __main__: app ListViewExample() app.run()配套的样式表list_view.tcssScreen { align: center middle; } ListView { width: 30; height: auto; margin: 2 2; } Label { padding: 1 2; }运行后你会看到一个居中的列表包含 One / Two / Three 三个条目底部是Footer会动态显示当前可用按键。用方向键移动高亮按 Enter 选中点击条目也可直接选中。要点拆解每个ListItem内部通常包裹一个Label作为文本内容但ListItem是普通Widget内部可以是任意内容图片、其他组件组合均可ListView作为容器子项通过compose或后续的append/extend等 API 添加样式表中height: auto让列表高度随子项数量自然伸缩。响应式属性indexListView只有一个核心响应式reactive属性NameTypeDefaultDescriptionindexint0当前高亮条目的索引。在源码中它被声明为index reactive[Optional[int]](None, initFalse)几点源码级细节值得注意默认值语义虽然文档表中标默认0但源码实现中index的初始值是None真正的高亮位置由构造函数参数initial_index默认0在挂载_on_mount时确定见 源码 _on_mount。当initial_index越界时会被重置为0若initial_index指定的项被禁用disabled则从该位置起向后循环查找第一个可用项。校验validate_index对index的赋值会经过 validate_index 夹取到合法范围小于 0 归 0大于等于子项数量归到最后一个索引列表为空时置为None。监听watch_indexwatch_index 在索引变化时负责三件事将新高亮项滚动到可视区域scroll_to_widget、清除旧项的-highlight、为新项设置-highlight并广播Highlighted消息。若新索引无效或指向被禁用项则广播的item为None。因此运行时可以这样读取/修改高亮# 读取当前高亮索引 current my_list_view.index # 直接跳到第 3 项会经过校验与监听自动触发滚动和消息 my_list_view.index 2消息Highlighted 与 SelectedListView通过两类消息与外部通信处理方式遵循 Textual 惯例——在父组件或App中定义on_list_view_highlighted/on_list_view_selected方法即可ListView.Highlighted当高亮项发生变化时发出例如按下上/下键移动光标见 源码 Highlighted。属性list_view所属列表、item新高亮项可为Nonecontrol属性是list_view的别名供on装饰器使用额外的消息匹配属性item已通过ALLOW_SELECTOR_MATCH {item}注册可以配合on(ListView.Highlighted, item...)做精细匹配。典型用法def on_list_view_highlighted(self, event: ListView.Highlighted) - None: if event.item is not None: label event.item.query_one(Label) self.status_bar.update(f当前高亮{label.renderable})ListView.Selected当用户选中条目时发出例如按下 Enter 或鼠标点击见 源码 Selected。属性list_view、item被选中的项、index选中项的索引同样支持on(ListView.Selected)装饰器匹配item也可作为匹配键。典型用法def on_list_view_selected(self, event: ListView.Selected) - None: self.log(f选中了第 {event.index} 项: {event.item})注意Highlighted在每次高亮移动时都会触发频率较高Selected只在确认选中时触发频率低两者分工明确适合分别驱动预览/详情与确认操作两类 UI 逻辑。按键绑定键盘导航ListView定义了三个按键绑定见 源码 BINDINGS| Key(s) | Description | | :- | :- | | enter | 选中当前条目。 | | up | 上移光标。 | | down | 下移光标。 |这三个绑定都声明为showFalse因此不会出现在Footer的默认按键提示中但ListView示例里Footer仍能显示 enter/up/down 相关提示因为 Footer 默认展示全局绑定如需让用户看到这些操作可以自行在应用层添加带描述的绑定。绑定背后的动作实现源码 actionsaction_cursor_down从当前索引向后查找下一个未禁用的项并高亮若当前无高亮则从第 0 项开始action_cursor_up对称地向前查找上一个未禁用项无高亮时从末尾项开始action_select_cursor取出当前高亮项并广播Selected消息若没有高亮项则直接返回。这里的关键细节是导航会跳过被禁用disabledTrue的ListItem见 tests/listview/test_listview_navigation.py 中的回归测试在 0、2、3、6、8 被禁用的列表中连续按 5 次 down 再 5 次 up高亮依次为1 → 4 → 5 → 7 → 5 → 4 → 1验证了跳过逻辑的确定性。鼠标交互虽然键盘是主要输入方式ListView同样支持完整的鼠标操作。其机制是ListItem捕获点击后向上抛出内部消息_ChildClickedListView通过_on_list_item__child_clicked接收并处理见 源码停止消息继续冒泡event.stop()将焦点转移到ListView本身self.focus()把index设置为被点击项的索引触发高亮更新与Highlighted广播Selected消息。相应地ListItem自己维护两个视觉状态见 ListItem 源码highlighted响应式属性由ListView写入通过watch_highlighted切换-highlightCSS 类鼠标悬停通过on(events.Enter)/on(events.Leave)设置-hovered类。动态增删项append / extend / insert / pop / clear / remove_itemsListView内置了完整的运行时增删API全部返回可等待对象配合await或App.run_async使用这在构建动态数据驱动的列表如文件列表、任务队列、日志流时非常关键方法作用返回类型append(item)在末尾追加一个ListItemAwaitMountextend(items)批量追加多个ListItemAwaitMountinsert(index, items)在指定索引处插入一个或多个ListItemAwaitMountpop(indexNone)移除最后一个或指定索引处的ListItemAwaitCompleteremove_items(indices)按索引批量移除多个ListItemAwaitCompleteclear()清空所有ListItemAwaitRemove实现要点见 源码 _list_view.py 动态 API 区段append/extend/insert都委托给容器的mount机制返回AwaitMount调用方可以用await list_view.append(...)等待 DOM 更新完成clear使用self.query(ListView ListItem).remove()移除全部直接子项并把index置为Nonepop在列表为空时会抛出IndexError(pop from empty list)该行为由 tests/listview/test_listview_remove_items.py 中的test_listview_pop_empty_raises_index_error测试锁定pop与remove_items在删除项后会自动校正高亮索引被删项位于高亮之前则索引前移删除的正是高亮项则触发索引重校验并手动调用watch_index确保-highlight与消息状态同步remove_items支持负索引归一化后批量删除并一次性地计算删除项位于高亮之前的数量来平移索引该行为同样有test_listview_remove_items回归测试覆盖。动态使用示例async def on_button_pressed(self) - None: # 动态追加 await self.list_view.append(ListItem(Label(新条目))) # 批量插入到开头 await self.list_view.insert( 0, [ListItem(Label(A)), ListItem(Label(B))] ) # 删除第 2 项0 起始 await self.list_view.pop(2)关于 initial_index 的边界行为构造函数的initial_index参数决定了列表首次挂载时的高亮位置默认0传None表示不预高亮任何项。源码_on_mount的边界处理src/textual/widgets/_list_view.py#L159-L170索引越界 子项数量时回退为0指向被禁用项时从该位置向后循环查找第一个可用的未禁用项因此initial_index指向禁用项时最终落点可能不是传入值而是向后找到的第一个可用项详见参数化测试 tests/listview/test_listview_initial_index.py例如 9 个条目中 0、2、3、6、8 禁用initial_index2时最终高亮4initial_index8时最终高亮1循环回绕。组件类Component ClassesListView没有定义任何组件类这是官方文档明确的结论。所有视觉定制都通过常规 CSS 选择器完成例如覆盖默认高亮配色ListView ListItem.-highlight { background: $accent; color: $text; }若需要在自定义场景中调整悬停/聚焦样式直接对.-hovered、.-highlight以及ListView:focus ListItem.-highlight写规则即可。与相近组件的选型对比如果你正在搭建选择类界面Textual 还提供若干与ListView定位相近的组件可参考官方 widgets 文档目录 按需选用OptionList面向纯文本选项 可选元数据的轻量列表API 更简单适合配置菜单、命令列表等无需复杂子内容结构的场景SelectionList带复选框的多选列表适合批量选择Select单行下拉选择器适合空间受限的表单场景Tree/DirectoryTree层级树形结构适合目录浏览等有父子关系的场景ListView的优势在于它是通用容器ListItem内部可以承载任意组件组合图片、进度条、按钮、嵌套布局等并自带完整的键盘导航、滚动跟随与动态增删 API是自由度最高的通用列表方案。小结ListView是一个开箱即用的垂直列表容器官方文档docs/widgets/list_view.md提供了最小示例与 API 总览而源码src/textual/widgets/_list_view.py与测试tests/listview/则进一步揭示了索引校验、禁用项跳过、滚动跟随、消息广播与动态增删的完整实现。掌握以下要点即可在生产代码中熟练使用用ListItem(Label(...))组合条目交给ListView统一管理焦点与高亮通过index响应式属性读写高亮通过Highlighted/Selected消息响应交互上下方向键导航会自动跳过disabled条目Enter 或点击触发选中用append/extend/insert/pop/remove_items/clear动态维护列表内容注意它们返回可等待对象视觉定制通过 CSS 对.-highlight、.-hovered与ListView:focus规则完成无需组件类。现在就可以参照 docs/examples/widgets/list_view.py 在终端里跑起你的第一个可键盘导航的 Textual 列表应用了。【免费下载链接】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),仅供参考

相关新闻

Kalibr多板同帧标定:原图复制+遮挡生成虚拟帧,精度0.2像素

Kalibr多板同帧标定:原图复制+遮挡生成虚拟帧,精度0.2像素

做相机标定的朋友,八成遇到过这种尴尬:采集的时候没注意,回看数据发现一帧画面里同时进了七八块标定板。常规做法是删掉这种“脏帧”重新拍,但如果项目已经收尾、现场设备都拆了,或者那组数据本身就是拿广角相机一次拍…

2026/9/21 1:24:35 阅读更多 →
二次元追番必备:5个站点组合,从看番到聊番一步到位

二次元追番必备:5个站点组合,从看番到聊番一步到位

玩二次元这些年,我手机里换过不少App,但真正常年留在收藏夹里的,反而是几个看起来并不“新潮”的网站。身边朋友经常问我:“你平时到底在哪看番?怎么找冷门老番?有些梗为什么弹幕刷得飞起我却看不懂&#x…

2026/9/21 22:15:09 阅读更多 →
Windows内存完整性完全指南:开启步骤、性能影响与驱动兼容性排查

Windows内存完整性完全指南:开启步骤、性能影响与驱动兼容性排查

1. 内存完整性到底是什么,为什么它总跑出来刷存在感先说结论:内存完整性是Windows安全体系里底层防线级的一个开关,系统默认不开启,但会在你打开“内核隔离”设置时反复进入视野。如果你最近在Windows安全中心里看到“内存完整性”…

2026/9/21 9:51:46 阅读更多 →

最新新闻

拒绝硬画:3步搞定初等函数图像渲染,性能提升5倍

拒绝硬画:3步搞定初等函数图像渲染,性能提升5倍

拒绝硬画:3步搞定初等函数图像渲染,性能提升5倍 官方文档里那些关于绘图库的API描述,动辄几十页,全是参数定义和数学公式,看完脑子还是浆糊。很多做数据可视化或者工程模拟的同行,一遇到 初等函数图像…

2026/9/21 23:49:35 阅读更多 →
告别只会背概念,这份蜡烛图保姆级教程带你搞定底层逻辑

告别只会背概念,这份蜡烛图保姆级教程带你搞定底层逻辑

告别只会背概念,这份蜡烛图保姆级教程带你搞定底层逻辑 看了一堆教程还是不会写项目?别急,问题往往出在你只记住了“长上影线是阻力”这种死板结论,却没搞懂K线背后的数据构成。今天这篇保姆级教程,不整虚的,直接拆解蜡烛图的底层原理,让你从代码层面…

2026/9/21 23:49:35 阅读更多 →
2016年2月日历图解原理:3个代码坑让你加班到凌晨

2016年2月日历图解原理:3个代码坑让你加班到凌晨

2016年2月日历图解原理:3个代码坑让你加班到凌晨 别再翻那几百页的官方文档了,抓不住重点就干瞪眼。今天用 图解原理 把2016年2月日历里的代码坑给你扒干净。…

2026/9/21 23:49:35 阅读更多 →
怎么学粤语入门到精通:解决版本升级后API全变了的性能优化实战

怎么学粤语入门到精通:解决版本升级后API全变了的性能优化实战

怎么学粤语入门到精通:解决版本升级后API全变了的性能优化实战 刚接手一个遗留的粤语语音识别模块,版本一升级,旧API全报404,接口文档里连个影子都找不到。这种“版本升级后 API…

2026/9/21 23:49:35 阅读更多 →
2012韦博英语价格表最佳实践与运维开发实战指南

2012韦博英语价格表最佳实践与运维开发实战指南

2012韦博英语价格表最佳实践与运维开发实战指南 很多刚入行的朋友,手里攥着几本语法书,背得滚瓜烂熟,一打开 IDE 就傻眼。不知道项目怎么搭,目录结构怎么理,更别提把代码跑起来变成真东西。这就是典型的“学会语法却不知怎么搭项目”。别慌,今…

2026/9/21 23:49:35 阅读更多 →
如何制作微信推送源码解析:3步搞定跑不通的代码

如何制作微信推送源码解析:3步搞定跑不通的代码

如何制作微信推送源码解析:3步搞定跑不通的代码 复制来的代码跑不通,是不是让你抓狂?报错信息像天书,调试半天没头绪。别急,今天咱们直接扒开【如何制作微信推送】的底层逻辑,用源码解析帮你理清思路。 一句话原理:回调机制与签名校验…

2026/9/21 23:48:35 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →