0

I was trying to create a simple app for illustration purposes. The idea is as follows: Create an application which will run script files associated only to the selected courses (radio buttons). So, I create radio buttons which list out subjects (to click on). Once the subjects are selected the user has to hit the Enter button. This should run all the .py files for the selected subjects (execute_script function).

However, when I run my code, I get 4 messageboxes with 'None' written inside. After clicking ok on them, I get a square windows with only the enter button. What can I do to correct this problem?

def check(file_name, relStatus):   
    radioValue = relStatus.get()
    tkMessageBox.showinfo('You checked', radioValue)
    been_clicked.append(file_name)   
    return

def execute_script():
    for name in been_cliked:
        subprocess.Popen(['python', 'C:\Users\Max\Subjects\{}'.format(name)])

    yield


def main():

    #Create application
    app = Tk()
    app.title('Coursework')
    app.geometry('450x300+200+200')

    #Header
    labelText = StringVar()
    labelText.set('Select subjects')

    #Dictionary with names
    product_names = {}
    names = []
    file_name = []
    names = ['Math', 'Science', 'English', 'French']
    file_name = ['calc.py', 'physics.py', 'grammar.py', 'livre.py']
    product_names = OrderedDict(zip(names, file_name))

    #Create radio buttons
    global been_clicked
    been_clicked = []
    relStatus = StringVar()
    relStatus.set(None)
    for name,file_name in product_names.iteritems():
        radio1 = Radiobutton(app, text=name, value=name, \
                         variable=relStatus, command=check(file_name, relStatus))

    button = Button(app, text='Click Here', width=20, command=execute_script())
    button.pack(side='bottom', padx=15, pady=15)

    app.mainloop()


if __name__ == '__main__': main()
Max Kim
  • 1,114
  • 6
  • 15
  • 28

1 Answers1

4

There are a few issues with your script:

1) A typo in your execute_script() function: for name in been_cliked

2) You are actually calling the check() function when you create your radio buttons. That's why you're seeing the windows pop up when you run your program.

You need to change this:

radio1 = Radiobutton(app, text=name, value=name, \
                     variable=relStatus, command=check(file_name, relStatus))

to this:

radio1 = Radiobutton(app, text=name, value=name, \
                     variable=relStatus, command=check)

See how check no longer has brackets? That's means you're passing the function name as an argument, instead of actually calling the function. Of course, you'll see an immediate problem is that you can no longer pass arguments to your callback function! That's a bigger issue. Here's a couple links to help get you started:

Here is the solution:

Change this:

command=check(file_name, reStatus)

to this:

command = lambda: check(file_name, relStatus)

3) You don't actually pack() your radio buttons anywhere. Add something like this just after you create your radio buttons in your for loop: radio1.pack(side='top')

4) You have the same problem with your callback for your Click Here button. You need to change your command to not call the function, but just refer to it: command = execute_script

5) In execute_script(), make sure you import subprocessing

6) Are you sure you want yield instead of return in your execute_script() function?

7) In all your functions, you need to make sure that been_clicked is global.

I think if you fix these issues you'll be closer to getting what you're looking for. Good luck.!

Community
  • 1
  • 1
supermitch
  • 2,062
  • 4
  • 22
  • 28
  • Strange that the `for name in been_cliked` problem doesn't result in a `NameError: global name 'been_cliked' is not defined` error since the `, command=execute_script()` is _calling_ `execute_script`. – martineau Jul 20 '13 at 15:40
  • I agree. The reason is he has `yield` instead of `return`. Using `yield` won't cause `NameError` to be raised. Not sure why that is though. – supermitch Jul 20 '13 at 15:45
  • 1
    Ah, the answer lies here: http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained `yield` causes a generator to be returned, but until that generated is used, the code hasn't been run yet. – supermitch Jul 20 '13 at 15:47
  • Indeed...mystery explained. To save folks the trouble of looking it up, here's the key paragraph about generator functions from @e-satis, et al's excellent answer: "To master yield, you must understand that **when you call the function, the code you have written in the function body does not run.** The function only returns the generator object, this is a bit tricky :-)" – martineau Jul 20 '13 at 18:17