You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Allow user to specify a custom to_str function for the ScrollMenu (and other similar widgets) that would be used to determine the line of text to display on the screen. Currently, only strings are allowed to be added to the widget.
Motivation? Imagine we had a list of Pet objects that might be defined as:
class Pet:
def __init__(self, name, breed, age):
self.name = name
self.breed = breed
self.age = age
def purchase(self):
print(f"You purchased a {self}")
def __str__(self):
return f"name={self.name} breed={self.breed} age={self.age}"
To display a list of pets and add an event handler for one that is selected in a ScrollMenu, I'd have to do the following:
pets = [Pet("Baloo", "Dog", 4), Pet("Wilbur", "Horse", 7)]
menu = root.add_scroll_menu("Pets", 0, 0)
menu.add_item_list(str(p) for p in pets) # explicitly convert to string
def process_selection():
selected_pet_text = menu.get()
for p in pets:
if str(p) == selected_pet_text:
p.purchase()
menu.add_key_command(py_cui.keys.KEY_ENTER, process_selection)
With a very small change to the code, users wouldn't have to look up which Pet was selected because the return value from ScrollMenu.get now returns the actual Pet object itself:
pets = [Pet("Baloo", "Dog", 4), Pet("Wilbur", "Horse", 7)]
menu = root.add_scroll_menu("Pets", 0, 0)
menu.add_item_list(pets) # Allow any object to be added
def process_selection():
selected_pet_object = menu.get() # this returns the object in the list
selected_pet_object.purchase() # so we can use it directly
menu.add_key_command(py_cui.keys.KEY_ENTER, process_selection)
Here is a custom MyScrollMenu that I built to add the above, but it the change is so minor and backwards compatible, that I think it should be added to the widget directly. In the custom widget, I've added one new parameter to the constructor: to_str. It has a default value of str. And then in the body of the ScrollMenu.draw method, only one line is changed—the in clause of the for loop:
class MyScrollMenu(py_cui.widgets.ScrollMenu):
def __init__(self, id, title, grid, row, column, row_span, column_span, padx, pady, to_str=str,
):
super().__init__(id, title, grid, row, column, row_span, column_span, padx, pady)
self.to_str = to_str
def draw(self):
super(py_cui.widgets.ScrollMenu, self).draw()
self.renderer.set_color_mode(
self.selected_color if self.selected else self.color
)
self.renderer.draw_border(self)
counter = self.pady + 1
line_counter = 0
for line in (self.to_str(i) for i in self.view_items):
if line_counter < self.top_view:
line_counter = line_counter + 1
else:
if counter >= self.height - self.pady - 1:
break
if line_counter == self.selected_item:
self.renderer.draw_text(
self, line, self.start_y + counter, selected=True
)
else:
self.renderer.draw_text(self, line, self.start_y + counter)
counter = counter + 1
line_counter = line_counter + 1
self.renderer.unset_color_mode(
self.selected_color if self.selected else self.color
)
self.renderer.reset_cursor(self)
Another nice item with this approach is that one can have multiple ScrollMenu widgets all containing the same Pet list, but each could be displayed differently just by passing a custom to_str function:
pets = [Pet("Baloo", "Dog", 4), Pet("Wilbur", "Horse", 7)]
menu1 = root.add_scroll_menu("Pets Detail", 0, 0)
menu1.add_item_list(pets) # Allow any object to be added
menu2 = root.add_scroll_menu("Pet Names", 0, 0, to_str=lambda p: p.name)
menu2.add_item_list(pets) # Allow any object to be added
The text was updated successfully, but these errors were encountered:
I like this idea. I want to finish some existing changes I am working on first that make pretty major structural changes to the internals of widgets/popups, and merge those in, and then we can take a look at adding this in the next set of changes.
I included this in the v0.1.1 release. At the moment it only supports using the __str__ function, though I may considering the ability to specify a different function in the future.
Allow user to specify a custom
to_str
function for theScrollMenu
(and other similar widgets) that would be used to determine theline
of text to display on the screen. Currently, only strings are allowed to be added to the widget.Motivation? Imagine we had a list of
Pet
objects that might be defined as:To display a list of pets and add an event handler for one that is selected in a
ScrollMenu
, I'd have to do the following:With a very small change to the code, users wouldn't have to look up which
Pet
was selected because the return value fromScrollMenu.get
now returns the actualPet
object itself:Here is a custom
MyScrollMenu
that I built to add the above, but it the change is so minor and backwards compatible, that I think it should be added to the widget directly. In the custom widget, I've added one new parameter to the constructor:to_str
. It has a default value ofstr
. And then in the body of theScrollMenu.draw
method, only one line is changed—thein
clause of thefor
loop:Another nice item with this approach is that one can have multiple
ScrollMenu
widgets all containing the samePet
list, but each could be displayed differently just by passing a customto_str
function:The text was updated successfully, but these errors were encountered: