Textual DataTable 重载后只显示表头宽度,按键后才恢复
Textual 8.2.8 同数据重载后,提前绘制可能缓存过窄的单元格。先区分数据与显示问题;允许固定列宽时使用 width,并检查不做按键操作时的完整画面。
Textual 的 DataTable 第一次显示完整,清空后重新填入同一批数据,却只剩表头那么宽的几字;按键、移动鼠标或改变窗口大小后又恢复。这种表现不一定是数据被清空,Textual 8.2.8 中还存在自动列宽与绘制缓存不同步的路径。
典型条件是重新加载之后、下一次空闲处理之前,表格已经绘制过一帧。name 表头只有几个字符,单元格原值为 a much longer name,界面却可能停留在 a mu。第二次内容与第一次一样、最终尺寸也一样时,重新测量列宽未必会产生能刷新缓存的尺寸变化。
先区分数据长度与屏幕上看到的长度
核对传入 add_row() 的值,以及表格读取到的单元格值。原值完整但屏幕截短,且一次窗口变化就恢复,才符合这一类绘制问题。若业务在传入前已经切片、格式化或覆盖字段,改绘制缓存不会恢复原始数据。
8.2.8 在空闲阶段更新列内容宽度,但行绘制缓存的键并不包含列宽。提前绘制的窄内容可以继续命中同一个缓存;普通的 refresh() 只是请求重绘,不应被当成清空所有内部缓存的保证。
列宽可以预先确定时,使用公开的固定宽度接口
业务允许固定宽度时,可以在重新添加列的同一阶段给出 width,不再依赖稍后自动测量。下面的宽度只适用于这个简单字符串示例:
from textual.widgets import DataTable
def reload_names(table: DataTable) -> None:
table.clear(columns=True)
table.add_column("name", key="name", width=24)
table.add_row("a much longer name", key="example")
width 的单位是终端显示单元格,不是 UTF-8 字节数。中文、组合字符、Rich 标记和可渲染对象都不能一律用 Python 的 len() 推算。真实内容可能超过 24 格时,应选择符合业务的宽度和滚动方式;上面的值不会保证任意文本完整显示。
clear(columns=True) 会移除原列,重新加列时须同步保留需要的列键、标签和顺序。原有行键、选择位置和滚动位置若需要恢复,也应由应用重新设置,不要只为解决宽度就悄悄丢掉这些状态。
必须自动列宽时,隔离兼容处理
需要根据任意内容自动测量的表格,不宜把固定宽度当成通用修复。8.2.8 的问题在内部测量后没有使全部旧绘制缓存失效;覆盖 _on_idle 或调用 _clear_caches 都依赖私有实现,应只在锁定版本、能维护回归用例的组件里评估,避免散落到每个加载回调。
单纯增加一个固定时长的 sleep 会依赖机器速度和终端调度。只让刷新键触发后恢复,也没有解决首次显示的错误。若等待后续版本提供修复,应核对实际发行内容和相同重载场景,不能只看到开发分支有修改就删掉兼容措施。
验收至少要包含首次加载、同数据重载、换成长短不同的数据,以及重载后不做任何按键或鼠标操作的静止画面。保留原来的窗口尺寸再检查一次;自动化检查若只读取单元格原值,会漏掉这种“数据正确、屏幕错误”的情况。


