管理到交互定制)
Textual Checkbox 組件完全指南從布爾狀態(tài)管理到交互定制【免費下載鏈接】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本文基于 Textual 官方文檔 docs/widgets/checkbox.md并結(jié)合源碼 src/textual/widgets/_checkbox.py、基類 src/textual/widgets/_toggle_button.py 與測試用例 tests/toggles/test_checkbox.py 展開帶你完整掌握 Textual 復選框組件的用法、事件模型與底層實現(xiàn)。Checkbox是 Textual 提供的一個輕量級復選框組件用于存儲一個布爾值True/False是構(gòu)建表單、設(shè)置頁、篩選器等界面時最常用的交互控件之一。本文將從零開始講解如何創(chuàng)建復選框、如何響應(yīng)其狀態(tài)變化事件、如何定制外觀樣式并深入到源碼層面剖析它的實現(xiàn)原理讓你在實戰(zhàn)中既能快速上手也能知其所以然。組件概覽Checkbox于 Textual 0.13.0 版本加入其定位非常簡單——存儲并展示一個布爾值。在組件特性上?可聚焦Focusable支持鍵盤操作可以被 Tab 鍵聚焦?非容器Not a Container不承擔布局容器職責不能作為其他控件的掛載點。從源碼結(jié)構(gòu)看Checkbox并不是從零實現(xiàn)的獨立控件而是繼承自內(nèi)部基類ToggleButton見 src/textual/widgets/_toggle_button.py。ToggleButton同時是Checkbox與RadioButton的公共核心因此復選框與單選按鈕在渲染、綁定、事件模型上高度同構(gòu)——復選框表示可獨立切換的布爾值單選按鈕則表示互斥選擇中的一項。# src/textual/widgets/_checkbox.py class Checkbox(ToggleButton): A check box widget that represents a boolean value.快速上手一個完整的示例應(yīng)用官方文檔在 docs/widgets/checkbox.md 中提供了一個展示復選框多種狀態(tài)的完整示例代碼位于 docs/examples/widgets/checkbox.py樣式表位于 docs/examples/widgets/checkbox.tcss。完整代碼如下from textual.app import App, ComposeResult from textual.containers import VerticalScroll from textual.widgets import Checkbox class CheckboxApp(App[None]): CSS_PATH checkbox.tcss def compose(self) - ComposeResult: with VerticalScroll(): yield Checkbox(Arrakis :sweat:) yield Checkbox(Caladan) yield Checkbox(Chusuk) yield Checkbox([b]Giedi Prime[/b]) yield Checkbox([magenta]Ginaz[/]) yield Checkbox(Grumman, True) yield Checkbox(Kaitain, idinitial_focus) yield Checkbox(Novebruns, True) def on_mount(self): self.query_one(#initial_focus, Checkbox).focus() if __name__ __main__: CheckboxApp().run()配套的樣式表Screen { align: center middle; } VerticalScroll { width: auto; height: auto; background: $boost; padding: 2; }示例的運行效果展示了復選框的各種形態(tài)純文本標簽如Checkbox(Caladan)Emoji 標簽Textual 支持富文本與 Emoji 簡寫:sweat:會被渲染為表情符號Rich 標記標簽[b]Giedi Prime[/b]使用粗體[magenta]Ginaz[/]使用洋紅色說明標簽天然支持 markup 語法默認勾選Checkbox(Grumman, True)、Checkbox(Novebruns, True)的第二個位置參數(shù)valueTrue使復選框初始即為選中狀態(tài)按 id 定位并聚焦idinitial_focus配合on_mount中的self.query_one(#initial_focus, Checkbox).focus()實現(xiàn)應(yīng)用啟動后自動聚焦指定復選框。在項目目錄下運行python docs/examples/widgets/checkbox.py即可看到該應(yīng)用的實際效果。復選框的選中項會顯示一個X標記未選中項則為空白框體選中的標簽顏色會變?yōu)閺娬{(diào)色。響應(yīng)式屬性Reactive AttributesCheckbox暴露了一個響應(yīng)式屬性value是組件唯一的公開狀態(tài)屬性NameTypeDefaultDescriptionvalueboolFalseThe value of the checkbox.該屬性在源碼中定義為見 src/textual/widgets/_toggle_button.pyvalue: reactive[bool] reactive(False, initFalse) The value of the button. True for on, False for off.reactive是 Textual 的響應(yīng)式系統(tǒng)參見 docs/api/reactive.md其核心行為由watch_value方法驅(qū)動見 src/textual/widgets/_toggle_button.pydef watch_value(self) - None: React to the value being changed. ... self.set_class(self.value, -on) self.post_message(self.Changed(self, self.value))從這段實現(xiàn)可以看出每次value變化會觸發(fā)兩件事同步切換 CSS 類set_class(self.value, -on)根據(jù)新值添加或移除-on類。選中時組件掛上-on類未選中時移除默認樣式表正是利用這個類來改變勾選標記的顏色派發(fā) Changed 消息向消息隊列投遞Changed事件供應(yīng)用層監(jiān)聽。注意初始化時不會觸發(fā)事件構(gòu)造函數(shù)中有一段關(guān)鍵邏輯見 src/textual/widgets/_toggle_button.py# NOTE: Dont send a Changed message in response to the initial set. with self.prevent(self.Changed): self.value value即通過prevent上下文管理器屏蔽了初始賦值產(chǎn)生的Changed消息——在compose階段用valueTrue創(chuàng)建的復選框不會在掛載時觸發(fā)on_checkbox_changed。這一點在測試 tests/toggles/test_checkbox.py 中也有明確斷言async def test_checkbox_initial_state() - None: The initial states of the check boxes should be as we specified. async with CheckboxApp().run_test() as pilot: assert [box.value for box in pilot.app.query(Checkbox)] [False, False, True] assert [box.has_class(-on) for box in pilot.app.query(Checkbox)] [ False, False, True, ] assert pilot.app.events_received []三個復選框初始值分別為False/False/True對應(yīng)的-on類也同步匹配而事件列表為空——證明初始化不產(chǎn)生Changed消息。消息事件Checkbox.ChangedCheckbox的文檔中只列出了一個消息Checkbox.Changed當復選框的值發(fā)生變化時觸發(fā)。在應(yīng)用類中通過約定命名的方法on_checkbox_changed即可接收并處理該事件例如class MyApp(App): def on_checkbox_changed(self, event: Checkbox.Changed) - None: self.notify(fCheckbox changed to: {event.value})從源碼見 src/textual/widgets/_checkbox.py來看Checkbox.Changed繼承自ToggleButton.Changed并在此基礎(chǔ)上提供了兩個便捷屬性class Changed(ToggleButton.Changed): Posted when the value of the checkbox changes. ... property def checkbox(self) - Checkbox: The checkbox that was changed. assert isinstance(self._toggle_button, Checkbox) return self._toggle_button property def control(self) - Checkbox: An alias for Changed.checkbox. return self.checkbox事件對象可用屬性匯總屬性類型說明event.valuebool變化后的值event.checkboxCheckbox觸發(fā)事件的復選框?qū)嵗蓮钠渖献x取id、value等event.controlCheckboxcheckbox的別名便于與 Textual 其他控件的事件接口保持一致測試 tests/toggles/test_checkbox.py 驗證了消息攜帶的信息以及checkbox與control的等價性async def test_checkbox_toggle() - None: Test the status of the check boxes after theyve been toggled. async with CheckboxApp().run_test() as pilot: for box in pilot.app.query(Checkbox): box.toggle() assert [box.value for box in pilot.app.query(Checkbox)] [True, True, False] assert [box.has_class(-on) for box in pilot.app.query(Checkbox)] [ True, True, False, ] await pilot.pause() assert pilot.app.events_received [ (cb1, True, True), (cb2, True, True), (cb3, False, True), ]注意該測試中的事件處理函數(shù)tests/toggles/test_checkbox.py同時用到了event.checkbox.id、event.checkbox.value以及event.checkbox event.control三者完整覆蓋了事件對象的全部接口。鍵位綁定BindingsCheckbox繼承自ToggleButton其鍵位綁定定義在基類中見 src/textual/widgets/_toggle_button.pyBINDINGS: ClassVar[list[BindingType]] [ Binding(enter,space, toggle_button, Toggle, showFalse), ]| Key(s) | Description | | :- | :- | | enter, space | Toggle the value. |也就是說在復選框獲得焦點時按下Enter或空格鍵即可切換選中狀態(tài)綁定使用showFalse因此不會出現(xiàn)在 Footer 的按鍵提示欄中綁定的 action 為toggle_button對應(yīng)基類方法action_toggle_button見 src/textual/widgets/_toggle_button.py內(nèi)部調(diào)用toggle()方法取反當前值。除了鍵盤鼠標點擊同樣可以切換狀態(tài)?;悓崿F(xiàn)了點擊事件處理器見 src/textual/widgets/_toggle_button.pyasync def _on_click(self, _: Click) - None: Toggle the value of the widget when clicked with the mouse. self.toggle()而toggle()本身只做一件事見 src/textual/widgets/_toggle_button.pydef toggle(self) - Self: Toggle the value of the widget. ... self.value not self.value return selfvalue變化后前面提到的watch_value會被響應(yīng)式系統(tǒng)自動調(diào)用進而同步-on類并派發(fā)Changed消息。因此鼠標點擊、鍵盤快捷鍵與編程式調(diào)用toggle()最終走的是同一條狀態(tài)更新鏈路。組件類Component ClassesCheckbox的外觀由兩個組件類Component Classes控制它們同樣繼承自ToggleButton見 src/textual/widgets/_toggle_button.pyCOMPONENT_CLASSES: ClassVar[set[str]] { toggle--button, toggle--label, }| Class | Description | | :- | :- | |toggle--button| Targets the toggle button itself. | |toggle--label| Targets the text label of the toggle button. |組件類與普通 CSS 類不同它們作用于控件內(nèi)部渲染的子區(qū)域用于細分樣式控制。在 CSS 中針對某個復選框定制時可以這樣使用Checkbox .toggle--button { color: $accent; } Checkbox .toggle--label { text-style: bold; }從渲染實現(xiàn)看見 src/textual/widgets/_toggle_button.pyrender()方法會分別獲取toggle--button與toggle--label的視覺樣式拼裝出「按鈕 標簽」的完整內(nèi)容其中按鈕部分由三個字符段組成BUTTON_LEFT ?、BUTTON_INNER X、BUTTON_RIGHT ▌見源碼 src/textual/widgets/_toggle_button.py左右側(cè)字符使用與背景融合的side_style從而呈現(xiàn)出一體化的勾選塊效果。構(gòu)造函數(shù)參數(shù)詳解Checkbox的完整構(gòu)造參數(shù)定義在基類ToggleButton.__init__中見 src/textual/widgets/_toggle_button.pydef __init__( self, label: ContentText , value: bool False, button_first: bool True, *, name: str | None None, id: str | None None, classes: str | None None, disabled: bool False, tooltip: RenderableType | None None, compact: bool False, ) - None:各參數(shù)說明如下參數(shù)類型默認值說明labelContentText復選框的文本標簽支持 Rich 標記markup與 Emoji 簡寫valueboolFalse初始值True表示選中注意初始化不觸發(fā)Changed消息button_firstboolTrue勾選塊是否位于標簽之前False時按鈕排在標簽之后namestr \| NoneNone組件名稱idstr \| NoneNoneDOM 中的唯一標識配合query_one定位使用classesstr \| NoneNone附加的 CSS 類disabledboolFalse是否禁用禁用后不可交互tooltipRenderableType \| NoneNone懸停提示內(nèi)容compactboolFalse是否啟用緊湊模式見下文其中l(wèi)abel的處理值得注意見 src/textual/widgets/_toggle_button.pydef _make_label(self, label: ContentText) - Content: Make label content. ... label Content.from_text(label).first_line.rstrip() return label標簽會被轉(zhuǎn)換為Content對象并僅保留首行first_line、去除尾部空白——多行標簽會被自動截斷為單行且支持運行期通過label屬性重新賦值賦值時會觸發(fā)refresh(layoutTrue)重繪。緊湊模式compactToggleButton還暴露了一個響應(yīng)式屬性compact見 src/textual/widgets/_toggle_button.pycompact: reactive[bool] reactive(False, toggle_class-textual-compact) Enable compact display?將compactTrue傳入構(gòu)造函數(shù)或在運行期設(shè)置checkbox.compact True組件會掛上-textual-compact類對應(yīng)的默認 CSS 會去掉邊框與內(nèi)邊距見 src/textual/widgets/_toggle_button.py使復選框在表格、列表等空間緊湊的場景下占用更小。樣式定制與默認 CSSCheckbox的默認外觀定義在基類的DEFAULT_CSS中見 src/textual/widgets/_toggle_button.py核心規(guī)則如下ToggleButton { width: auto; border: tall $border-blurred; padding: 0 1; background: $surface; text-wrap: nowrap; text-overflow: ellipsis; pointer: pointer; ... }要點解讀尺寸width: auto讓復選框?qū)挾入S內(nèi)容自適應(yīng)text-wrap: nowrap防止標簽換行過長文本以省略號截斷邊框border: tall $border-blurred使用雙線模糊邊框聚焦時切換為$border高亮指針pointer: pointer讓鼠標懸停時顯示手型指針提示可點擊選中態(tài):on即掛有-on類的狀態(tài)此時勾選塊前景色變?yōu)?text-success見 src/textual/widgets/_toggle_button.py聚焦態(tài):focus時邊框加粗并給標簽套上$block-cursor-*背景色懸停blur:hover時標簽背景變?yōu)?block-hover-backgroundANSI 終端適配:ansi規(guī)則為不支持真彩色的終端提供了降級配色見 src/textual/widgets/_toggle_button.py。在業(yè)務(wù)應(yīng)用中覆蓋這些默認樣式時可以基于組件類或狀態(tài)類編寫更高優(yōu)先級的規(guī)則例如Checkbox { background: $panel; padding: 1 2; } Checkbox.-on .toggle--button { color: $success; text-style: bold; }在真實界面中的組合用法Textual 自帶的演示應(yīng)用 src/textual/demo/widgets.py 展示了Checkbox與RadioButton、RadioSet的典型組合場景class Checkboxes(containers.VerticalGroup): Demonstrates Checkboxes. DEFAULT_CSS Checkboxes { height: auto; Checkbox, RadioButton { width: 1fr; } ... } def compose(self) - ComposeResult: yield Markdown(self.CHECKBOXES_MD) yield Checkbox(A Checkbox) yield RadioButton(A Radio Button) yield RadioSet( Amanda, Connor MacLeod, ... )從該示例的 CSSCheckbox, RadioButton { width: 1fr; }可以看出復選框經(jīng)常被放進VerticalGroup、HorizontalGroup等容器中通過1fr均分寬度實現(xiàn)整齊的列表布局。選擇建議當需要多個可獨立開/關(guān)的布爾開關(guān)時用Checkbox當需要一組互斥選項、只能選其一時用 RadioButton 配合RadioSet。二者共享ToggleButton基類因此本文介紹的事件模型、綁定方式與組件類體系對單選按鈕同樣適用。常見實戰(zhàn)模式小結(jié)編程式取值/設(shè)值直接讀寫checkbox.value或調(diào)用checkbox.toggle()取反響應(yīng)式系統(tǒng)會自動同步界面。響應(yīng)變化在應(yīng)用或容器上定義on_checkbox_changed(self, event: Checkbox.Changed)通過event.checkbox.id區(qū)分是哪個復選框發(fā)生了變化。動態(tài)修改標簽checkbox.label 新標簽即可熱更新標簽文本無需重建組件。定位復選框self.query_one(#some_id, Checkbox)按 id 獲取實例self.query(Checkbox)獲取全部復選框。禁用交互Checkbox(只讀項, disabledTrue)使復選框不可點擊、不可聚焦。測試驅(qū)動使用App.run_test()配合Pilot見 docs/api/pilot.md可以在無終端環(huán)境下斷言value、-on類與事件序列官方測試 tests/toggles/test_checkbox.py 就是可直接參考的范例。結(jié)語Checkbox雖然只存儲一個布爾值但其背后凝聚了 Textual 響應(yīng)式屬性、消息事件、鍵位綁定、組件類樣式與 ANSI 適配等多套核心機制。通過本文你不僅掌握了它的全部 API 用法——value屬性、Checkbox.Changed事件、enter/space鍵位、toggle--button/toggle--label組件類與完整構(gòu)造參數(shù)——也借助 src/textual/widgets/_toggle_button.py 與 tests/toggles/test_checkbox.py 理解了其狀態(tài)同步鏈路與初始化語義。下一步你可以直接運行示例應(yīng)用或參考 docs/widgets/checkbox.md 及 widget 總覽 探索更多組件?!久赓M下載鏈接】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創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考