Shiroslullaby
Shiroslullaby

Reputation: 129

Python Tkinter radio buttons from a dictionary list

I've got an Excel spreadsheet I'm pulling info from. This will probably be changed to a database at some point but for now its fine for testing. It has two columns with data and looks like:

Key    |    ProgramName    |     Path

0      |    Calculator     |     C:\Windows\System32\calc.exe
1      |    Notepad        |     C:\Windows\System32\notepad.exe 

I've built a pretty basic GUI using Python Tkinter and use the xlrd library to extract data from the spreadsheet into a list that contains dictionary entries.
https://pypi.python.org/pypi/xlrd

This gives me a list with dictionary entries:

 [{'Path':'C:\Windows\System32\notepad.exe', 'Program':'Notepad', 'Key':0.0}, {'Path':'C:\Windows\System32\calc.exe', 'Program':'Calculator', 'Key':1.0}]

I can get the radio buttons working decently but I'm having an issue pulling the path data and re-using it, since I will (hopefully) use subprocess.Popen to actually open the program selected.

Heres the code so far:

from Tkinter import *
from xlrd import open_workbook
import os
import subprocess

class App:

def __init__(self, master):

    frame = Frame(master)
    frame.pack()

    bottomframe= Frame(master)
    bottomframe.pack(side = BOTTOM)

    book = open_workbook('programlist.xls')
    sheet = book.sheet_by_index(0)

    # read header values into the list    
    keys = [sheet.cell(0, col_index).value for col_index in xrange(sheet.ncols)]

    global dict_list
    dict_list = []
    for row_index in xrange(1, sheet.nrows):
        d = {keys[col_index]: sheet.cell(row_index, col_index).value 
            for col_index in xrange(sheet.ncols)}
        dict_list.append(d)

    self.w = StringVar()
    self.w.set(dict_list[0]['Key']) # initialize

    for eachprogram in dict_list:
        self.c = Radiobutton(master, text=eachprogram['Program'], variable=self.w, value=eachprogram['Key'])
        self.c.pack(anchor=W)


    self.quitButton = Button(
        bottomframe, text="QUIT" , fg="red", command=frame.quit
        )
    self.quitButton.pack(side=LEFT, anchor=S)


    self.programRun = Button(bottomframe, text="Run", command=self.programRun)
    self.programRun.pack(side=LEFT, anchor=S)


def programRun(self):
    ???

root = Tk()

app = App(root)

root.mainloop()
root.destroy()

Not sure what I need to do so that when the programRun button is pressed, correct path is pulled so I can put it into a "subprocess.Popen" command. Do I need to create another variable? Can I pull this info using a dictionary key?

Any suggestions are greatly appreciated.

Upvotes: 1

Views: 1210

Answers (1)

CommonSense
CommonSense

Reputation: 4482

It's not a hard task to pull path from your example and here're even two options to choose from. And you don't need to create an another variable.

According to Docs:

The variable option must be set to a control variable, either an IntVar or a StringVar. All the radiobuttons in a functional group must share the same control variable.

Set the value option of each radiobutton in the group to a different value. Whenever the user sets a radiobutton, the variable will be set to the value option of that radiobutton, and all the other radiobuttons that share the group will be cleared.

As you see - you don't need to use a StringVar, but DoubleVar since your value parameters (and keys) are floats. Downside here - you need to iterate over list to check each dictionary for Key.

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.frame = tk.Frame(self)
        self.frame.pack()

        self.bottomframe = tk.Frame(self)
        self.bottomframe.pack(side=tk.BOTTOM)

        # book = open_workbook('programlist.xls')
        # sheet = book.sheet_by_index(0)

        # read header values into the list
        # keys = [sheet.cell(0, col_index).value for col_index in xrange(sheet.ncols)]

        self.keys = ['Key', 'ProgramName', 'Path']
        self.dict_list = [{'Path': r'C:\Windows\System32\notepad.exe', 'Program': 'Notepad', 'Key': 0.0},
                          {'Path': r'C:\Windows\System32\calc.exe', 'Program': 'Calculator', 'Key': 1.0}]

        # global dict_list
        # dict_list = []
        # for row_index in xrange(1, sheet.nrows):
        #    d = {keys[col_index]: sheet.cell(row_index, col_index).value
        #       for col_index in xrange(sheet.ncols)}
        #    dict_list.append(d)

        self.w = tk.DoubleVar()
        self.w.set(self.dict_list[0]['Key'])  # initialize

        for each_program in self.dict_list:
            self.c = tk.Radiobutton(self.master, text=each_program['Program'], variable=self.w, value=each_program['Key'])
            self.c.pack(anchor=tk.W)


        self.quitButton = tk.Button(
            self.bottomframe, text="QUIT", fg="red", command=self.frame.quit
            )
        self.quitButton.pack(side=tk.LEFT, anchor=tk.S)


        self.programRun = tk.Button(self.bottomframe, text="Run", command=self.programRun)
        self.programRun.pack(side=tk.LEFT, anchor=tk.S)

    def programRun(self):
        print('Pulled path: %s' % self.search_list_dict())

    def search_list_dict(self):
        try:
            return [item for item in self.dict_list if item['Key'] == self.w.get()][0]['Path']
        except IndexError:
            return ''

app = App()
app.mainloop()

As an alternative - you can use a StringVar and Path item as a value parameter! Just change some lines:

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        ...
        self.w = tk.StringVar()
        self.w.set(self.dict_list[0]['Path'])  # initialize

        for each_program in self.dict_list:
            self.c = tk.Radiobutton(self.master, text=each_program['Program'], variable=self.w, value=each_program['Path'])
            self.c.pack(anchor=tk.W)
        ...

    def programRun(self):
        print('Pulled path: %s' % self.w.get())

app = App()
app.mainloop()

Upvotes: 1

Related Questions