-
Hi There Before I post a bug, I ask the question, if I did something wrong. Use case In an app with multiple screens, I need a refresh mechanism because the data could have changed. As a solution, I pop and push the screen ( Symptoms
Questions
Thank you very much for your inputs. The example below shows the symptom in the console:
from textual.app import App, ComposeResult
from textual.screen import Screen
from textual.binding import Binding
from textual.containers import Container
from textual.widgets import Header, Footer, Static, Input
from textual.css.query import TooManyMatches
from textual import log
class HomeScreen(Screen):
DEFAULT_CSS = """
Input.red-border {
border: tall $error;
}
"""
def compose(self) -> ComposeResult:
yield Header()
yield Footer()
yield Container(
Static("Home Screen"),
Static("Press <f> to find the input:"),
Input(placeholder="I change the border when pressing <f>",
id="id_of_input_widget"),
Static(
"Press <ctrl+r> to refresh the screen (pop, push): <f> will find multiple Inputs"),
)
class RefreshExampleApp(App):
SCREENS = {
"home": HomeScreen(),
}
BINDINGS = [
Binding("f", action="finds_input", description="Find Input"),
Binding("ctrl+r", action="refresh_screen", description="Refresh"),
]
def on_mount(self) -> None:
self.push_screen("home")
def action_refresh_screen(self) -> None:
self.pop_screen()
self.push_screen(HomeScreen())
def action_finds_input(self) -> None:
log("---=== screen_stack === ---")
for screen in self.screen_stack:
log("screen:", screen, screen.name)
log("*** children ***")
log("len: ", len(self.children))
for child in self.children:
log("child:", child)
try:
# self.get_widget_by_id("id_of_input_widget").toggle_class("red-border")
self.query_one("#id_of_input_widget").toggle_class("red-border")
log("Toggle class succeeded")
log("- nr of inputs: ", len(self.query(Input)))
log("- nr of #ids: ", len(self.query("#id_of_input_widget")))
except TooManyMatches:
log("Toggle class not possible")
log("- nr of inputs: ", len(self.query(Input)))
log("- nr of #ids: ", len(self.query("#id_of_input_widget")))
if __name__ == "__main__":
app = RefreshExampleApp()
app.run() |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
I guess I immediately found the problem, when publishing the discussion and read through my own question... def on_mount(self) -> None:
self.push_screen("home")
def action_refresh_screen(self) -> None:
self.pop_screen()
self.push_screen(HomeScreen()) During mount, I push the screen with the name as a string def on_mount(self) -> None:
self.push_screen(HomeScreen())
def action_refresh_screen(self) -> None:
self.pop_screen()
self.push_screen(HomeScreen()) Conclusion: I should take care to work with the same identifiers: either string or class, do not mix. |
Beta Was this translation helpful? Give feedback.
-
I ran into a similar issue. For me, however, it is not related to the fact that I'm pushing/switching screens in 2 ways - once with a string and once with a newly created object. When I use predefined screens in the SCREENS variable at all - duplicates are indicated in the DOM even though the stack of screens seems to be fine (there is only 1 screen with some widget I used for the query). It's not a isue if Idon't use SCREENS at all and all screens are changed by the creation of new objects. Unfortunately, my example is more complicated and I can't show you the simple code that causes this behavior, but I can assure you that when I consistently use changing screens with strings, the problem occurs, and when I do that by creating objects, it disappears. @davep I also do not understand why elements in the DOM would be duplicated even when using inconsistent switching of screens - once in this way and once in the other? this looks like a bug, and if not, can someone explain to me why this is happening even though everything is fine in the screens stack? |
Beta Was this translation helpful? Give feedback.
I guess I immediately found the problem, when publishing the discussion and read through my own question...
During mount, I push the screen with the name as a string
"home"
, as defined inSCREENS
. By pressing ctrl+r I push the screen by it's class name:HomeScreen()
. Changing it to the following, solves the problem:Conclusion: I should …