Python Forum
[PyGUI] Getting values from ButtonGroup
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGUI] Getting values from ButtonGroup
#1
Hi,
I have just started using guizero on a Raspberry Pi4 and I have hit a wall. I followed the tutorial for theater tickets and it worked as stated. I am trying to use the GUI as a basis for relay control and I substituted GPIO statements to turn on relays. What doesn't work is that when I try to use the value of "row_choice" in an IF statement I get no results from the GPIO. If I substitute print statements for the GPIO.output statement nothing prints. It seems that I can only print the value befor the If statement. I must have something wrong in the IF statement but after consulting the manual i can't find it.
Thanks in advance for any help.
Chris
from guizero import App,ButtonGroup,PushButton,info
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(14,GPIO.OUT)
GPIO.setup(15,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
app = App(title="Antenna", width=300, height=200, layout="grid")
row_choice = ButtonGroup(app, options=[ ["Long wire", 1], ["SlimJim", 2],["10m", 3],["Off", 0] ],selected=0, horizontal=True, grid=[1,2], align="left")

def do_booking():
    info("", "Selected")
    print(row_choice.value)
    if (row_choice.value)==1:
        GPIO.output(18,GPIO.HIGH)
    elif (row_choice.value)==0:
        GPIO.output(18,GPIO.LOW)

book_seats = PushButton(app, command=do_booking, text="Select", grid=[1,3], align="left")

app.display()
Reply
#2
guizero is so friendly that even if you pass the incorrect attribute it works.
what is row_choice.value?
print(type(row_choice.value))
Reply
#3
It should detect the integer 1 when I choose "Long Wire" and turn on GPIO 18. I tried the character "1" as well but that didn't work either.The GPIO statements work when placed outside of the IF loop. It seems that the IF is not working.
Reply
#4
Regardless of the type you provide for "value" it becomes a string when you call ButtonGroup.value. It really limits the usefulness of providing a value for the button.

I wanted to provide a function as the second argument. When I asked the ButtonGroup to return the options the functions were still there. When I selected a button the value was the __repr__ string for the function. So I made my own map between key and value.
from guizero import App, ButtonGroup

functions = {
    'A': lambda: print('Aye'),
    'B': lambda: print('Bee'),
    'C': lambda: print('Sea')}
choices = list(functions.keys())

def selected():
    functions[row_choice.value]()

app = App(title="Test", width=100, height=100)
row_choice = ButtonGroup(
    app,
    options=choices,
    selected=choices[0],
    command=selected)

app.display()

What do you mean by this?

Quote: I tried the character "1" as well but that didn't work either.

In the code below I use "1" and "0" when checking the group button value and it works fine. I think it is stupid code, but it works.
from guizero import App, ButtonGroup

def selection():
    if row_choice.value == '1':
        print('GPIO.output(18,GPIO.HIGH)')
    elif row_choice.value == '0':
        print('GPIO.output(18,GPIO.LOW)')

app = App(title="Test", width=300, height=200, layout="grid")
row_choice = ButtonGroup(
    app,
    options=[
        ["Long wire", 1],
        ["SlimJim", 2],
        ["10m", 3],
        ["Off", 0]],
    selected='0',
    horizontal=True,
    grid=[1,2],
    align="left",
    command=selection)
app.display()
If you compare the button value, and the button value is a string, it makes more sense to use a descriptive string like "Off" instead of "0".
from guizero import App, ButtonGroup

def selection():
    if row_choice.value == 'Long wire':
        print('GPIO.output(18,GPIO.HIGH)')
    elif row_choice.value == 'Off':
        print('GPIO.output(18,GPIO.LOW)')

app = App(title="Test", width=300, height=200, layout="grid")
row_choice = ButtonGroup(
    app,
    options=["Long wire", "SlimJim",  "10m", "Off"],
    selected='Off',
    horizontal=True,
    grid=[1,2],
    align="left",
    command=selection)
app.display()
Reply
#5
(Mar-30-2021, 06:58 PM)deanhystad Wrote: Regardless of the type you provide for "value" it becomes a string when you call ButtonGroup.value. It really limits the usefulness of providing a value for the button.

I wanted to provide a function as the second argument. When I asked the ButtonGroup to return the options the functions were still there. When I selected a button the value was the __repr__ string for the function. So I made my own map between key and value.
from guizero import App, ButtonGroup

functions = {
    'A': lambda: print('Aye'),
    'B': lambda: print('Bee'),
    'C': lambda: print('Sea')}
choices = list(functions.keys())

def selected():
    functions[row_choice.value]()

app = App(title="Test", width=100, height=100)
row_choice = ButtonGroup(
    app,
    options=choices,
    selected=choices[0],
    command=selected)

app.display()

What do you mean by this?

Quote: I tried the character "1" as well but that didn't work either.

In the code below I use "1" and "0" when checking the group button value and it works fine. I think it is stupid code, but it works.
from guizero import App, ButtonGroup

def selection():
    if row_choice.value == '1':
        print('GPIO.output(18,GPIO.HIGH)')
    elif row_choice.value == '0':
        print('GPIO.output(18,GPIO.LOW)')

app = App(title="Test", width=300, height=200, layout="grid")
row_choice = ButtonGroup(
    app,
    options=[
        ["Long wire", 1],
        ["SlimJim", 2],
        ["10m", 3],
        ["Off", 0]],
    selected='0',
    horizontal=True,
    grid=[1,2],
    align="left",
    command=selection)
app.display()
If you compare the button value, and the button value is a string, it makes more sense to use a descriptive string like "Off" instead of "0".
from guizero import App, ButtonGroup

def selection():
    if row_choice.value == 'Long wire':
        print('GPIO.output(18,GPIO.HIGH)')
    elif row_choice.value == 'Off':
        print('GPIO.output(18,GPIO.LOW)')

app = App(title="Test", width=300, height=200, layout="grid")
row_choice = ButtonGroup(
    app,
    options=["Long wire", "SlimJim",  "10m", "Off"],
    selected='Off',
    horizontal=True,
    grid=[1,2],
    align="left",
    command=selection)
app.display()



Thanks for the suggestions everyone.
I think that the info function had some effect on the if statement. I got rid of it and now the IF works as expected. Now on to the next problem. All works well until the program tries to set the GPIO outputs, I get the following errors.

Python 3.7.3 (/usr/bin/python3)
>>> %Run Antenna.py
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/usr/lib/python3/dist-packages/guizero/ButtonGroup.py", line 313, in _command_callback
self._command()
File "/home/pi/Desktop/Antenna.py", line 12, in do_booking
GPIO.output(18,GPIO.HIGH)
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

I do have the GPIO.setmode(GPIO.BCM) in the beginning of the program. It seems like they do not work inside of the function. I am only starting to become familiar with python so I may have forgotten something.

from guizero import App,ButtonGroup,PushButton,info
import RPi.GPIO as GPIO
GPIO.setwarnings (False)
GPIO.setmode (GPIO.BCM)
GPIO.setup (24,GPIO.OUT)
GPIO.setup (25,GPIO.OUT)
GPIO.setup (18,GPIO.OUT)
app = App(title="Antenna Relay", width=300, height=50, layout="grid")

def do_booking():
if (row_choice.value)==("L"):
GPIO.output(18,GPIO.HIGH)
elif (row_choice.value) == ("S"):
GPIO.output(24,GPIO.HIGH)
elif (row_choice.value) == ("M"):
GPIO.output(25,GPIO.HIGH)
elif (row_choice.value) == "O":
GPIO.output(18,GPIO.LOW),GPIO.output(24,GPIO.LOW),GPIO.output(25,GPIO.LOW)
row_choice = ButtonGroup(app,command=do_booking, options=[ ["Long wire", "L"], ["SlimJim", "S"],["10m", "M"],["Off", "O"] ],selected=0, horizontal=True, grid=[1,2], align="left")
GPIO.cleanup()
app.display()
Reply
#6
You need to wrap code in python tags so the indenting is saved.

I believe your error was something else. info does not have any affect on getting the button group value. That the code started working when you removed the info call is likely a coincidence.

If you want to initialize the button group you need to use a value from the group.
row_choice = ButtonGroup(
    app,
    command=do_booking,
    options=[
        ["Long wire", "L"],
        ["SlimJim", "S"],
        ["10m", "M"],
        ["Off", "O"]],
    selected=0,  # <- Not a value in list.  Use "O"?
    horizontal=True,
    grid=[1,2],
    align="left")
What is this?
    GPIO.output(18,GPIO.LOW),GPIO.output(24,GPIO.LOW),GPIO.output(25,GPIO.LOW)
I doubt this code does not do what you think it does. You can put multiple commands on one line, but they have to be separated by semicolons. What you are doing is making a tuple.
a = 1, 2, 3, 4
print(a)
Output:
(1, 2, 3, 4)
Since you are not assigning the tuple to a variable, and all you are interested in is the side effect of calling GPIO.output(), your tuple does the same thing as this.
    GPIO.output(18,GPIO.LOW);GPIO.output(24,GPIO.LOW);GPIO.output(25,GPIO.LOW)
But it is a bad idea writing code that you don't understand that just happens to do what you want. You shouldn't put multiple python commands in the same line anyway. It is hard to read. Instead do this:
    elif (row_choice.value) == "O":
        GPIO.output(18,GPIO.LOW)
        GPIO.output(24,GPIO.LOW)
        GPIO.output(25,GPIO.LOW)
Though I don't know what you are trying to do I am pretty sure this code is wrong.
    if (row_choice.value)==("L"):
        GPIO.output(18,GPIO.HIGH)
    elif (row_choice.value) == ("S"):
        GPIO.output(24,GPIO.HIGH)
    elif (row_choice.value) == ("M"):
        GPIO.output(25,GPIO.HIGH)
    elif (row_choice.value) == "O":
        GPIO.output(18,GPIO.LOW)
        GPIO.output(24,GPIO.LOW)
        GPIO.output(25,GPIO.LOW)
You are using a button group to set the pins. The button group allows only one choice. With your code you could set all the pins high, but the button group would still show only one selected. If you want the ability to turn multiple pins high at the same time you should use a different GUI control, like a checkbox for each pin. If you want to only set one pin high at a time your code is wrong.

I think your problem with GPIO is caused by this command.
GPIO.cleanup()
According to the docs
Quote:RPi.GPIO provides a built-in function GPIO.cleanup () to clean up all the ports you’ve used. But be very clear what this does. It only affects any ports you have set in the current program. It resets any ports you have used in this program back to input mode.
You are setting all the ports to input mode and then trying to treat them like outputs. The cleanup command should appear after the app.display() command.

I do not have a device to run this code, but this is how I would write your program going on the assumption that you want to be able to set the output pins 1 at a time.
from guizero import App, ButtonGroup
import RPi.GPIO as GPIO

# Dictionary mapping pin names to pins
output_pins = {
    "Off":None,  # Not a pin.  To turn all pins off
    "Long wire":18,
    "SlimJim":24,
    "10m":25}

def set_output():
    """Set selected output pin high, all other pins low"""
    for pin in output_pins.values():
        if pin is not None:
            GPIO.output(pin, GPIO_LOW)
    pin = output_pins.get(pin_group.value, None)
    if pin is not None:
        GPIO.output(pin, GPIO_HIGH)
 
# Configure the pins
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
for pin in output_pins.values():
    if pin is not None:
        GPIO.setup(pin, GPIO.out)

app = App(title="Antenna Relay", width=300, height=50, layout="grid")
pin_group = ButtonGroup(
    app,
    command=set_output,
    options=output_pins.keys(),
    selected="Off",
    horizontal=True,
    grid=[1,2],
    align="left")
app.display()
GPIO.cleanup()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020