Doug Luce
Doug Luce

Reputation: 93

Having some trouble getting which radio button is selected and issuing a command based on the selection

I'm writing a program that converts an image to grayscale. I have it working fine and now I'm implementing radio buttons to let the user choose which type of grayscale to use. So far my problem is that when the radio buttons are first made the command = function is called immediately and sets all of my boolean values to True, as that's explicitly what I'm telling it to do by passing using function() instead of function. I'm trying to think of a way that I can use to store which radio button is selected, or hoping that there is something built in that I can do the check for. I do know that using global variables is not best practice, and that a class would eliminate the necessity for them. Here is the relevant code.

# Global variables for radio buttons----
radio1 = False
radio2 = False
radio3 = False
radio4 = False

def whichSelected(numberSelected):
    global radio1
    global radio2
    global radio3
    global radio4
    if numberSelected == 4:
        radio4 = True
    if numberSelected == 3:
        radio3 = True
    if numberSelected == 2:
        radio2 = True
    if numberSelected == 1:
        radio1 = True

# Radio Button Code---------------------------------------------------------
var = tkinter.IntVar()
option1 = tkinter.Radiobutton(window, text ='Average Grayscale',variable = var, value = 1,command =  whichSelected(1))
option2 = tkinter.Radiobutton(window, text ='Lightness Grayscale',variable = var, value = 2, command = whichSelected(2))
option3 = tkinter.Radiobutton(window, text ='Luminosity Grayscale',variable = var, value = 3, command = whichSelected(3))
option4 = tkinter.Radiobutton(window, text ='Invert',variable = var, value = 4, command = whichSelected(4))

def change_pixel():
    global tkPic2
    global radio1
    global radio2
    global radio3
    global radio4
    # Treats the image as a 2d array, iterates through changing the
    #values of each pixel with the algorithm for gray
    rgbList = pic.load() #Get a 2d array of the pixels
    for row in range(picWidth):
        for column in range(picHeight):
            rgb = rgbList[row,column]
            r,g,b = rgb # Unpacks the RGB value tuple per pixel
            if radio1 == True:
                grayAlgorithm1 = grayAverage(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio2 == True:
                grayAlgorithm = lightness(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)
            elif radio3 == True:
                grayAlgorithm1= luminosity(r,g,b)
                rgbList[row,column] = (grayAlgorithm1, grayAlgorithm1, grayAlgorithm1)     # Gives each pixel a new RGB value
            elif radio4 == True:
                r,g,b= invertRGB(r,g,b)
                rgbList[row,column] = (r, g, b) # Gives each pixel a new RGB value
        # Converting to a tkinter PhotoImage
    tkPic2 = ImageTk.PhotoImage(pic, master = window)
    print(radio1,radio2,radio3,radio4)
    canvas1.create_image(815,170, anchor='e',image = tkPic2)

Upvotes: 1

Views: 1880

Answers (1)

mgilson
mgilson

Reputation: 309891

I'm not completely sure why you need whichSelected in the first place. You should be able to tell from the value of var:

value = var.get()
if value == 1:
    print "Average Grayscale"
elif value == 2:
    print "Lightness Grayscale"
...

This has the added benefit of guaranteeing that you know which value is currently checked. With your previous approach, you need to add some logic to turn all the all the globals to False before making the one you want True. As your function is, if the user selects one of the radio buttons and then another, both will be marked as True in your global variables.


However, it's instructive to point out why your approach is failing as well. In addition to the problem previously mentioned, the command argument is supposed to be a function, you're passing the result of a function (in this case None). When you call the functions to get the result, you're setting your globals to True as a side-effect.

The quick fix is to use lambda to create a new function which calls the old one the way you want to. This way, you will defer setting the globals to True until your radio button is actually clicked:

option1 = tkinter.Radiobutton(window, text='Average Grayscale',
                                      variable=var,
                                      value=1,
                                      command=lambda: whichSelected(1))

lambda ends up being very useful for this sort of thing in tkinter applications. (I can't imagine writing an app without it ...)

Upvotes: 2

Related Questions