MyreMylar / pygame_gui

A GUI system for pygame.
MIT License
698 stars 83 forks source link

UIListBox - add option for always one item selected (use in drop down) #363

Open Toma400 opened 1 year ago

Toma400 commented 1 year ago

Describe the bug While selecting listbox entry, their recognition works randomly, unless I un-select the entry (in such case, recognition is fully reliable).

To Reproduce Steps to reproduce the behaviour:

  1. Create listbox and some variable to store listbox output (name of element chosen), so event.text won't be empty
  2. Create event system which overwrites variable with current event.text when entry is clicked, and with None when it is unclicked
  3. Let the program print the entry name when you click on button and variable value is not None

Expected behaviour App should print entry name no matter how I clicked on it - be it by un-selecting, on simply switching from one entry to another.

Screenshots Video instead: https://user-images.githubusercontent.com/65849429/204492359-ee0edac7-80b1-4965-9c3b-867f44ef9001.mp4

Platform and software (please complete the following information):

Additional context Workspace on which I worked on - L12/L27/L29 is variable system allowing me to store text passed from listbox, on L34 I try to print it when correct button is clicked and entry is selected

MyreMylar commented 1 year ago

I feel like the logic needs to be improved here. You don't know the order pygame_gui.UI_SELECTION_LIST_NEW_SELECTION and pygame_gui.UI_SELECTION_LIST_DROPPED_SELECTION will be fired in when switching selected items (it depends on the order they are in the UI items list) so the code as you have it will not work.

Instead do something like this:

for event in pg_events:
            if event.type == pygame.QUIT or pygame.key.get_pressed()[pygame.K_ESCAPE]:
                con.append("end")

            if event.type == pygame_gui.UI_SELECTION_LIST_NEW_SELECTION:
                bcs_events["sl_in"] = event.ui_element

            if event.type == pygame_gui.UI_BUTTON_PRESSED:
                if event.ui_element == guiobj.login__enter and bcs_events["sl_in"].get_single_selection() is not None:
                    print (bcs_events["sl_in"].get_single_selection())

            pg_gui.process_events(event)

Basically it is pretty easy to get the currently selected item in a single selection list box if you have a reference to the list box, so I would do it that way when you press the log in button.

The list selection events are really intended for doing something specifically when an item is selected or unselected (e.g. play a sound effect, create some sparkly particles), not for getting the current state of the list. You could do that from these events but you'd need to track the list state yourself.

Simple state checks are what the get_single_selection() and get_multi_selection() functions are for (which you use depends on the type of list box).

Anyway, I do think the interactions events for this element could be clearer (I think it should be possible to make a list box where something must always be selected - for example), I'll make another pass over it for 0.7.0.

Toma400 commented 1 year ago

Thank you for amazing response! Your code snippet indeed clears this greatly, as I haven't known about get_n_selection() from documentation provided on website, so went the route it felt more natural for the system.

I also wanted to drop words of appreciation - although PyGame GUI feels not yet as complex for me to take it into my main game I talked on Reddit (though I'd love to drop the idea or two), it feels like exactly on point for side-project as here. I really like how nicely it intertwines with PyGame system and theme customisation is interesting, to say the least.