ppizarror / pygame-menu

A menu for pygame. Simple, and easy to use
https://pygame-menu.readthedocs.io/
Other
544 stars 141 forks source link

file selector #461

Closed gonensel closed 1 year ago

gonensel commented 1 year ago

Hello I wold like to know if there is a file selector or something like that I can get a file from the user? Thanks Gonen

leestarb commented 1 year ago

Hello! Not sure whether there is a module for OS oriented file operation management. I suggest you using the plyer module. It works with several OSes. I also use it.

ppizarror commented 1 year ago

Hi @gonensel, implementing file selectors is difficult because it must provide too many options, filters, folders, file extensions, events, etc. I would rather use your OS file selector through tkinter module; see https://stackoverflow.com/questions/63801960/how-to-prompt-user-to-open-a-file-with-python3.

It is preferable because the OS file selector maps your drives, network drives, home folder, paths to the desktop, downloads, multiple selections, copy/paste, copy to address bar, etc. Implementing this is very complex because it must be consistent on every OS.

If you still need a file selector, you can use os.listdir to retrieve the folders, and the results can be inserted into a DropSelect widget, https://pygame-menu.readthedocs.io/en/4.4.0/_source/add_widgets.html#add-a-drop-selection. After the value of the dropselect changes, it must update the folders/files within it using onchange method; however, it would still be very basic.

gonensel commented 1 year ago

hi @ppizarror thanks for the answer ! I have another questions: 1.there is a way to make all buttons in the same size? 2.while I am using text input on every input I get it twice there is a way to stop it? in the events there is two key down events

ppizarror commented 1 year ago

Hi, for your questions:

  1. You can use many hacks; for example, use a decorator that draws a fixed rectangle of your desired area. The other alternative is to define a maximum allowable width, and for those widgets that are less than the target, just incorporate more padding. I've created the following example that applies a target width for the widgets:
import pygame
import pygame_menu

pygame.init()
surface = pygame.display.set_mode((600, 400))

menu = pygame_menu.Menu('Welcome', 400, 300, theme=pygame_menu.themes.THEME_BLUE)

def set_widget_size(widget: 'pygame_menu.widgets.Widget', target: int = 300):
    # In this method, we will iterate each widget and try to setup
    # a width of 300px. If the widget has a smaller width, we will
    # increase its padding; else, we will resize it
    widget_size = widget.get_size(apply_padding=False)
    if widget_size[0] >= target:
        widget.set_max_width(target, scale_height=False)
    else:
        # We setup the padding as the half remaining between the target and the
        # current width for left/right, and 4px for top/bottom (we could have
        # retrieved its original value, but it is just a simple test!! =) )
        widget.set_padding((4, (target - widget_size[0]) / 2))

menu.add.button('Play', lambda: print('Nice'))
menu.add.button('This is a very long button omg', None)
menu.add.button('Quit', pygame_menu.events.EXIT)

for w in menu.get_widgets():
    set_widget_size(w)

menu.mainloop(surface)

Result:

image

This set_widget_size is not within any menu API because there is no a "global" solution for this problem, as there are many potential solutions; hence, a common method would not fit each usage case. You could also have used widget.resize(300, 40) to any widget, but the results are not great depending on each specific case.

  1. This could happen because of many reasons. a) you do not limit the number of fps of your menu execution; therefore, your app might be running at 300 fps, which queries each event hundreds of times each second. Thus, any event keyboard could have been repeated in a very small window span. To overcome that issue, limit the number of frames by using the clock.tick; see https://stackoverflow.com/questions/34383559/pygame-clock-tick-vs-framerate-in-game-main-loop. b) To overcome the repeating keys, the textinput widget considers a "time span threshold" in milliseconds; if a key is detected in a window period less than, let's say, 30ms, it is ignored. This input value is named as repeat_keys_interval_ms; see docs https://pygame-menu.readthedocs.io/en/4.4.1/_source/widgets_textinput.html#pygame_menu.widgets.TextInput. Then you can set up a larger value, and just heuristically test which value fits your app, for example:
menu.add.text_input(..., repeat_keys_interval_ms=300)

Again, there is no global solution for this; it depends on each particular case. This issue is also "related" to #422. It is not the same but also relates to the event repetition. This problem is very common within any MVC app. You can also create your Controller object, but this is far more difficult as it requires you to map the input time series, create filtering rules, etc.

PD: It is important to comment that the menu does not introduce new events; thus, each "duplicated" event you see comes from your own OS trying to deal with multiple inputs simultaneously.

ppizarror commented 1 year ago

Hi, I'll close this issue as completed. Greetings 😃.