Repository navigation
How to set a default option for a Selection element #3976
|
I'm making a language learning app which uses a text-to-speech library to pronounce numbers in different languages. I have the following list of dicts (abridged for brevity): self.languages = [
{"name" : "English (United Kingdom)", "lang" : "en", "accent" : "co.uk" },
{"name" : "English (United States)", "lang" : "en", "accent" : "us" },
{"name" : "French (France)", "lang" : "fr", "accent" : "fr" },
{"name" : "Portuguese (Brazil)", "lang" : "pt", "accent" : "com.br" },
{"name" : "Spanish (Spain)", "lang" : "es", "accent" : "es" },
]This list is the content of a toga Selection element, as I learned to do from the Toga documentation: self.language_dropdown = toga.Selection(items=self.languages, accessor="name")I'm happy that this is properly configured because a function elsewhere in my code makes use of the currently selected language: tts = gTTS(text=f"{self.number}", lang=f"{self.language_dropdown.value.lang}", tld=f"{self.language_dropdown.value.accent}")That is to say, the dropdown is doing what I want it to, I have no problem there. self.language_dropdown = toga.Selection(items=self.languages, accessor="name", value="French (France)"
self.language_dropdown = toga.Selection(items=self.languages, accessor="name", value=self.languages[2])
self.language_dropdown = toga.Selection(items=self.languages, accessor="name", value="fr")Whatever I put, I get a ValueError: {'name': 'English (United Kingdom)', 'lang': 'en', 'accent': 'co.uk'} is not a current item in the selectionI'm a little frustrated to be stuck on something so basic, and would appreciate any advice on this! |
Replies: 4 comments 4 replies
|
In this case, it's not your fault - this is an area of Toga's API that could definitely be improved. The issue is that the value of The best workaround right now is to construct the Selection in two parts. You can do this in one of two ways. Firstly, you can construct the selection as you have here, then set the value afterward. By setting the data, that will construct the data source, and you can then
The other approach you can take is to explicitly create your data source, and then provide that to the Selection: I completely agree that neither of these approaches are especially intuitive. However, I think there would be a relatively straightforward fix/enhancement. The setter for |
|
For what it's worth: I typically end up wrapping selections as follows (see example below):
I do realize and appreciate that Toga wants to make it easy to store data directly in the user interface components. But for larger and more complex applications I prefer to decouple user interface and business logic / domain. I do like the approach where you can store additional data in the selection, since it allows to do things like this. I also use such an approach with tables sometimes, where you can simply store an id or an object next to the text fields accessed by the accessors. This does not solve the value in constructor issue above however, but I just to a set_value after creation. |
|
Very interesting discussion .... With "directly in the user interface components" I actually meant "in the Toga layer of the application". I am looking from the application perspective of course and I still consider the Source API as Toga. I probably do not understand the Source API correctly, but I (maybe wrongfully) did not give it too much attention since I do not want to couple my model/domain/business logic layer tightly with my user interface/presentation layer. I do not know if the Source API allows that. The application I am working on follows a library <> apps (ui, command line, ...) approach and I need a fallback for Toga (tkinter, which I hope I will not need). In my example above, it means that Language is a model/domain/business logic object that lives in the library (anyway) and also needs to work with a tkinter or command line app. The example is a bit misleading because it is so simple, but Language could also be a ResultSet class with 1M complex records that requires pagination to display. So maybe I should look into building a custom ListSource that bridges between my library / ResultSet on the one side and Toga on the other side. But I have not looked into that yet. One reason is that my datasets are too large for a Toga table to efficiently display. To be completely honest, I also did not want to spend the time to reverse-engineer ListSource from the source code (because docs are not great, which given the < 1.0 state of the project is of course fully acceptable) to come to the conclusion it would not support my use case. Especially if a custom layer on top would also easily support tkinter. But again, our perspectives of course differ. What I guess I meant to say is that the Source API is great, but for larger / more complex applications you will probably have to build a layer on top or extend it anyway? It would be great of course if both use cases are supported well. But again, I might not be understanding the Source API correctly. I will happily look into it in the future if you think it can support a use case like mine (lazy loading, pagination, lazily converting rows to display values, custom filtering and sorting). It would make life easier in fact, except if it turns out that I will not be able to use Toga in the end, which was in fact a second reason for not diving into it, since my current code should be easily portable to tkinter. |
|
Thanks for the continued discussion, I think I'm starting to get a sense of what I need to do here. I have two questions if I may impose further:
|
In this case, it's not your fault - this is an area of Toga's API that could definitely be improved.
The issue is that the value of
valueneeds to be aRowobject - the internal representation of each item of content in the data. The complication is that it's not easy to get a Row object in the constructor.The best workaround right now is to construct the Selection in two parts. You can do this in one of two ways.
Firstly, you can construct the selection as you have here, then set the value afterward. By setting the data, that will construct the data source, and you can then
findthe row for the item you want: