6

I want use PySimpleGui to dynamically create radio buttons from a list, but my efforts to insert a loop in the layout code are catching syntax errors. Can this be done with the API or do I need to slog it out with tkinter? My list is being generated by a targeted file search of a network drive.

I've tried concatenating 'layout', putting the radio button section in a for loop. Also attempted to insert a for loop in the [sg.Radio()] declaration itself. Neither works.

import PySimpleGUI as sg

xList = ['a', 'b', ... 'zz']

layout = [[sg.Text('Select a thingy')],
          [sg.Radio(<for thingy in xList: 'thingy', thingy>)],
                   #^^^^^^ for loop is psuedo code
          [sg.OK(), sg.Cancel()]]
OldFartN00B
  • 61
  • 1
  • 3

1 Answers1

9

I think this is what you're looking for?

import PySimpleGUI as sg

radio_choices = ['a', 'b', 'c']
layout = [
            [sg.Text('My layout')],
            [sg.Radio(text, 1) for text in radio_choices],
            [sg.Button('Read')]
         ]

window = sg.Window('Radio Button Example', layout)

while True:             # Event Loop
    event, values = window.Read()
    if event is None:
        break
    print(event, values)

It produces this window:

enter image description here

There are a number of ways of "building" a layout variable. Here are a couple of other combinations that produce the same window:

This first one builds one row at a time and then adds them together in the end

# Build Layout
top_part = [[sg.Text('My layout')]]
radio_buttons = [[sg.Radio(x,1) for x in radio_choices]]
read = [[sg.Button('Read')]]
layout = top_part + radio_buttons + read

This one also builds a single row at a time and then adds them together, but it does it in a single statement instead of 4.

   # Build layout
    layout = [[sg.Text('My layout')]] + \
                [[sg.Radio(text, 1) for text in radio_choices]] + \
                [[sg.Button('Read')]]

If you wanted to add these buttons one per line, then there are several ways of doing this too. If you are using Python 3.6, then this will work:

layout = [
            [sg.Text('My layout')],
            *[[sg.Radio(text, 1),] for text in radio_choices],
            [sg.Button('Read')]
         ]

The "Build a layout" technique will work on systems where the above * operator is not valid.

radio_choices = ['a', 'b', 'c']
radio = [[sg.Radio(text, 1),] for text in radio_choices]
layout = [[sg.Text('My layout')]] + radio + [[sg.OK()]]

Both of these variations when combined with the window code and the event loop, will produce a window that looks like this: enter image description here

Mike from PSG
  • 5,312
  • 21
  • 39
  • Thank you for your speedy response and multiple examples that are all spot-on. Is there a way to have each radio button in a separate row? I tried including "\n" as part of each item in my list and this only caused the text to be slightly offset from the RB. If the list is short, the single row is fine. – OldFartN00B May 22 '19 at 20:51
  • 1
    OK, I've edited the answer to include methods of making the radio buttons on individual rows. Was there no good documentation or example programs that showed how to do something like this? Where would you have looked in the docs or in the sample programs? Like what's a Demo Program name for something like this? "Programatically built layouts" ' – Mike from PSG May 22 '19 at 23:47
  • A sizable section has been added to the documentation that is devoted to creating layouts using code. This question was an excellent one as it spurred quite a bit of research and ultimately documenting a number of Pythonic ways of generating windows. It's fun to use a list comprehension to make entire windows. Readme and ReadTheDocs were updated. – Mike from PSG Sep 03 '19 at 21:49
  • 1
    Although OP didn't ask... the solution doesn't assign a key to the group. This means it can't be updated dynamically. Or am I missing something @Mike-from-PSG? – Jay Marm May 12 '21 at 01:55