jeudi 8 juin 2017

Python - Radio Button or Check Box Variables Cause "Is Not Defined" Error

I'm having difficulty with Python 3.6.1 and a GUI utilizing TKinter that I built with the help of the PAGE GUI builder. When I try to get the output of radio buttons or check boxes, I'm getting an error such as:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\...\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
    return self.func(*args)
  File "C:\Users\...\Test\DemTRAN_SpecInstrs.py", line 252, in click_btnNext
    stateSpecInstrs = selectRdo.get()
NameError: name 'selectRdo' is not defined
>>> 

In my program, the user is asked whether any additional special information is required for a medical exam. Two radio buttons at the top prompt the user to select either No (default) or Yes. There are also a series of checkboxes and a text field for "Other" information, with "Next" and "Cancel" buttons at the bottom. When the user clicks the "Next" button at the bottom of the GUI, one of two things should happen based on the radio button selection:

  • If the user selects "No," one set of data will go to a text file, and Notepad will open so the user can copy the data into the Remarks block of another program.
  • If the user selects "Yes," another set of data will go to the text file, based on which checkboxes are selected and if the user writes in the text field.

(I tried but failed to add a photo of the GUI. Sorry!)

Unlike the examples I've come across in StackExchange and the rest of the Internet, PAGE does not build everything in a single .py file. It builds the GUI in the main .py file and puts global variables into the support file. I suspect this is where the problem arises, but I can't figure out the resolution.

Here is the code for the support.py file:

#! /usr/bin/env python
#
# Support module generated by PAGE version 4.9
# In conjunction with Tcl version 8.6
#    Jun 07, 2017 04:00:21 PM


import sys

try:
    from Tkinter import *
except ImportError:
    from tkinter import *

try:
    import ttk
    py3 = 0
except ImportError:
    import tkinter.ttk as ttk
    py3 = 1

def set_Tk_var():
    global combobox
    combobox = StringVar()
    global vSpecInstrsCheck1
    vSpecInstrsCheck1 = StringVar()
    global vSpecInstrsCheck2
    vSpecInstrsCheck2 = StringVar()
    global vSpecInstrsCheck3
    vSpecInstrsCheck3 = StringVar()
    global vSpecInstrsCheck4
    vSpecInstrsCheck4 = StringVar()
    global vSpecInstrsCheck5
    vSpecInstrsCheck5 = StringVar()
    global vSpecInstrsCheck6
    vSpecInstrsCheck6 = StringVar()
    global vListofInstrs
    vListofInstrs = StringVar()
    global vSpecInstrs
    vSpecInstrs = StringVar()

def init(top, gui, *args, **kwargs):
    global w, top_level, root
    w = gui
    top_level = top
    root = top

def destroy_window():
    # Function which closes the window.
    global top_level
    top_level.destroy()
    top_level = None

if __name__ == '__main__':
    import DemTRAN_SpecInstrs
    DemTRAN_SpecInstrs.vp_start_gui()

Here is some of the code from the main file:

#! /usr/bin/env python
#
# GUI module generated by PAGE version 4.9
# In conjunction with Tcl version 8.6
#    Jun 07, 2017 04:00:12 PM
import sys
import os

# try deleted from this sample

import DemTRAN_SpecInstrs_support

def vp_start_gui():
    '''Starting point when module is the main routine.'''
    global val, w, root
    root = Tk()
    DemTRAN_SpecInstrs_support.set_Tk_var()
    top = SPECIAL_INSTRUCTIONS (root)
    DemTRAN_SpecInstrs_support.init(root, top)
    root.mainloop()

w = None
def create_SPECIAL_INSTRUCTIONS(root, *args, **kwargs):
    '''Starting point when module is imported by another program.'''
    global w, w_win, rt
    rt = root
    w = Toplevel (root)
    DemTRAN_SpecInstrs_support.set_Tk_var()
    top = SPECIAL_INSTRUCTIONS (w)
    DemTRAN_SpecInstrs_support.init(w, top, *args, **kwargs)
    return (w, top)

def destroy_SPECIAL_INSTRUCTIONS():
    global w
    w.destroy()
    w = None


class SPECIAL_INSTRUCTIONS:
    def __init__(self, top=None):
        '''This class configures and populates the toplevel window.
           top is the toplevel containing window.'''

# Code relating to background/foreground color omitted for clarity

        # Re-define global variable to fix radio button issue
        selectRdo = IntVar()
        selectRdo = DemTRAN_SpecInstrs_support.vSpecInstrs
        selectRdo.set(0)

        self.btnNext = Button(top)
        self.btnNext.place(relx=0.28, rely=0.9, height=34, width=87)
        self.btnNext.configure(activebackground="#d9d9d9")
        self.btnNext.configure(activeforeground="#000000")
        self.btnNext.configure(background="#d9d9d9")
        self.btnNext.configure(disabledforeground="#a3a3a3")
        self.btnNext.configure(foreground="#000000")
        self.btnNext.configure(highlightbackground="#d9d9d9")
        self.btnNext.configure(highlightcolor="black")
        self.btnNext.configure(pady="0")
        self.btnNext.configure(text='''Next''')
        self.btnNext.configure(command=self.click_btnNext)

# Only one checkbutton shown.  Others omitted for clarity
        self.gSpecInstrsCheck5 = ttk.Checkbutton(top)
        self.gSpecInstrsCheck5.place(relx=0.22, rely=0.5, relwidth=0.3
                , relheight=0.0, height=21)
        self.gSpecInstrsCheck5.configure(variable=DemTRAN_SpecInstrs_support.vSpecInstrsCheck5)
        self.gSpecInstrsCheck5.configure(takefocus="")
        self.gSpecInstrsCheck5.configure(text='''Send to provider in Bend area''')

        self.gSpecInstrsNo = Radiobutton(top)
        self.gSpecInstrsNo.place(relx=0.45, rely=0.1, relheight=0.05
                , relwidth=0.07)
        self.gSpecInstrsNo.configure(activebackground="#d9d9d9")
        self.gSpecInstrsNo.configure(activeforeground="#000000")
        self.gSpecInstrsNo.configure(background="#d9d9d9")
        self.gSpecInstrsNo.configure(disabledforeground="#a3a3a3")
        self.gSpecInstrsNo.configure(foreground="#000000")
        self.gSpecInstrsNo.configure(highlightbackground="#d9d9d9")
        self.gSpecInstrsNo.configure(highlightcolor="black")
        self.gSpecInstrsNo.configure(justify=LEFT)
        self.gSpecInstrsNo.configure(text='''No''')
        self.gSpecInstrsNo.configure(value=0)
        # self.gSpecInstrsNo.configure(variable=DemTRAN_SpecInstrs_support.vSpecInstrs)
        self.gSpecInstrsNo.configure(variable=selectRdo)
        self.gSpecInstrsNo.configure(command=self.btnNext)

        self.gSpecInstrsYes = Radiobutton(top)
        self.gSpecInstrsYes.place(relx=0.45, rely=0.14, relheight=0.05
                , relwidth=0.08)
        self.gSpecInstrsYes.configure(activebackground="#d9d9d9")
        self.gSpecInstrsYes.configure(activeforeground="#000000")
        self.gSpecInstrsYes.configure(background="#d9d9d9")
        self.gSpecInstrsYes.configure(disabledforeground="#a3a3a3")
        self.gSpecInstrsYes.configure(foreground="#000000")
        self.gSpecInstrsYes.configure(highlightbackground="#d9d9d9")
        self.gSpecInstrsYes.configure(highlightcolor="black")
        self.gSpecInstrsYes.configure(justify=LEFT)
        self.gSpecInstrsYes.configure(text='''Yes''')
        self.gSpecInstrsYes.configure(value=1)
        # self.gSpecInstrsYes.configure(variable=DemTRAN_SpecInstrs_support.vSpecInstrs)
        self.gSpecInstrsYes.configure(variable=selectRdo)
        self.gSpecInstrsYes.configure(command=self.btnNext)   


    def click_btnNext(self):
        # stateSpecInstrs = selectRdo.get()
        # if stateSpecInstrs == 1:
            # f = open("output.txt","w")
            # f.write("Test output for DemTRAN \n")
            # f.write("More test output for DemTRAN \n")
            # f.write("********************************")
            # f.close()
            # os.startfile('output.txt')
        # else:
            # f = open("output.txt","w")
            # f.write("Special instructions:  No \n")
            # f.write("Continue with other text \n")
            # f.write("********************************")
            # f.close()
            # os.startfile('output.txt')

        x = vSpecInstrsCheck5.get()
        if x == "1":
            f = open("output.txt","w")
            f.write("******************************** \n")
            f.write("SPECIAL INSTRUCTIONS \n")
            f.write("Send to provider in Bend area \n")
            f.write("******************************** \n")
            f.close()
            os.startfile('output.txt')

I commented out the "if" statements for the radio button just to see if the behavior was different with the check box. It wasn't.

Curiously, I had to hack this a bit because when I'd run the program, both the No and Yes radio buttons were selected. The user could still select Yes or No and only the active button would be blacked out, but I found this behavior bothersome. I found an article online where a user had the same problem, and the recommended fix was to create a new variable in the class to stand in for the original variable. That fixed the problem. In troubleshooting, I removed that and restored the original variable to see if that made a difference. Assuming I restored every reference to the original value, it didn't change anything.

The "Next" and "Cancel" buttons at the bottom work. To test the "Next" button, I simply had it print dummy data to a text file and then open that file to display the contents. Things broke down when I tried to make the "Next" button send data based on the No or Yes radio button selection.

Any help on where I'm going wrong with my [variable].get()? Thanks!




Aucun commentaire:

Enregistrer un commentaire