-
I am trying to implement a Of course I could use composition but that would be a secondary resort. from typing import Any, Generator
from textual import containers
from textual.app import App, ComposeResult
from textual.widgets import Label, TabbedContent, TabPane
method = 2
def create_tabs() -> Generator[Label, Any, None]:
with TabPane("1"):
with containers.Center():
yield Label("Asd")
with TabPane("2"):
with containers.Center():
yield Label("Bsd")
class DerivedTabbedContent(TabbedContent):
def compose(self) -> ComposeResult:
# Neither of these will work but if not like this then how?
if method == 1:
# Will hang badly
with self:
yield from create_tabs()
elif method == 2:
# Won't hang but doesn't quite do what's needed
yield from create_tabs()
yield from super().compose()
class OkApp(App):
# Works as expected
def compose(self) -> ComposeResult:
with TabbedContent():
yield from create_tabs()
class FailingApp(App):
# Would love if it worked
def compose(self) -> ComposeResult:
yield DerivedTabbedContent()
def cli():
run_problematic = True
if run_problematic:
FailingApp().run()
else:
OkApp().run() |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
Well, my workaround is this at this point:
from typing import Any, Generator
from textual.app import App, ComposeResult
from textual.widget import Widget
from textual.widgets import Label, TabbedContent, TabPane
class PotentiallySelfComposingTabbedContentLikeWidget(Widget):
DEFAULT_CSS = """
PotentiallySelfComposingTabbedContentLikeWidget {
width: 1fr;
height: 1fr;
overflow: hidden hidden;
border: round $foreground 20%;
}
"""
_initial: str
_use_example_data: bool
_tabs: list[TabPane]
def __init__(self, *, initial: str = "", use_example_data: bool = False, **kwargs):
super().__init__(**kwargs)
self._initial = initial
self._use_example_data = use_example_data
self._tabs = []
def compose(self) -> ComposeResult:
with TabbedContent(initial=self._initial):
if self._use_example_data:
yield from self.create_example_tabs()
yield from self._tabs
def compose_add_child(self, widget: Widget) -> None:
if not isinstance(widget, TabPane):
raise TypeError(
f"widget should be of type {TabPane.__name__}, got {type(widget).__name__} instead"
)
self._tabs.append(widget)
def create_example_tabs(self) -> Generator[Widget, Any, None]:
with TabPane("1"):
yield Label("Not cats here!")
with TabPane("2"):
yield Label("No cats here either!")
class DemoApp(App):
def compose(self) -> ComposeResult:
with PotentiallySelfComposingTabbedContentLikeWidget(initial="cats", use_example_data=True):
with TabPane("3", id="cats"):
yield Label("Cats!") |
Beta Was this translation helpful? Give feedback.
-
With non-negligible compromise children can be added using inheritence: from typing import Any, Generator
from textual import containers
from textual.app import App, ComposeResult
from textual.widget import Widget
from textual.widgets import Label, TabbedContent, TabPane
def create_tabs() -> Generator[Label, Any, None]:
with TabPane("1"):
with containers.Center():
yield Label("Asd")
with TabPane("2"):
with containers.Center():
yield Label("Bsd")
def create_tabs_no_context() -> list[Widget]:
return [
TabPane("1", containers.Center(Label("Asd"))),
TabPane("2", containers.Center(Label("Bsd"))),
]
class DerivedTabbedContent(TabbedContent):
def __init__(self, method):
self.method = method
super().__init__()
def compose(self) -> ComposeResult:
# Only `no-context-3` does what's required, we are constrained to use constructor based widget assembly
# syntax however.
#
# Not a huge surprise as `Widget.__enter__`/`__exit__` modify states at the top of the hierarchy. Still I'd expect some way to do this.
#
# You would need to prepend to `_tab_content` instead of extend if you want to have widgets added after
# this class adds its own tabs.
if self.method == "context-1":
# Will hang badly
with self:
yield from create_tabs()
elif self.method == "context-2":
# Won't hang but doesn't quite do what's needed
yield from create_tabs()
elif self.method == "context-3":
# Nope
self._tab_content.extend(create_tabs())
elif self.method == "no-context-1":
# Nope, hang
with self:
yield from create_tabs_no_context()
elif self.method == "no-context-2":
# Nope
yield from create_tabs_no_context()
elif self.method == "no-context-3":
# Yes
self._tab_content.extend(create_tabs_no_context())
yield from super().compose()
class CompositionApp(App):
# Works as expected
def compose(self) -> ComposeResult:
with TabbedContent():
yield from create_tabs()
class InheritenceApp(App):
# But, I want to derive from TabbedContent:
def compose(self) -> ComposeResult:
yield DerivedTabbedContent(method="no-context-3")
def cli():
InheritenceApp().run() |
Beta Was this translation helpful? Give feedback.
-
Please explain why you think you need this, as there is almost certainly a better solution. |
Beta Was this translation helpful? Give feedback.
Well, my workaround is this at this point: