1

I am trying to create a framework to create a label, text box and button as an object, I can extend it easily.

Idea:

Original

after extend

and it could extend to have 3, 4, 5 or more if it have more file, just declare in dictionary list, it will extend automatically.

The code I have:

def getpath(entry_box, type):
# path or file
if type == 'path':
    entry_box.set(filedial.askdirectory())
elif type == 'file':
    entry_box.set(filedial.askopenfilename())

MainWin = tk.Tk() # Create main windows
MainWin.title('Get file and path') # App name

# Create root container to hold Frames
mainFrame = ttk.Frame(MainWin)
mainFrame.grid(column=1, row=1)
# define the object to create in dictionary, format:
# {object name:[title name, default path, button name, file or folder path]}
obj2create ={'file1':['ABC Location: ', r'C:/', 'Get ABC','file'],
             'file2': ['DEF Location:', r'C:/1/', 'Get DEF', 'file']}
ttl_obj = 0
for key in obj2create:
    ttl_obj +=1
    vir = obj2create[key]
    # Module for get file:
    obj_name = key
    title = vir[0]
    default_path = vir[1]
    btn_name = vir[2]
    get_type = vir[3]

    # Create main container
    pa_frame = ttk.Frame(mainFrame)
    pa_frame.grid(column=1, row=10*ttl_obj, sticky=tk.W)
    pa_frame.config(width = 100)
    # Row 1: Label
    frame_name = obj_name + '_name'
    print(frame_name)
    frame_name = ttk.Label(pa_frame, text= title).grid(column=1, row=10*ttl_obj,sticky=tk.W)
    # Row 2: path and button
    # assign type
    path_loc = obj_name + '_path'
    path_loc = tk.StringVar()
    path_loc.set(default_path)
    # put in frame
    fileLocPath = obj_name + '_loc_path'
    fileLocPath = ttk.Entry(pa_frame, width=70, textvariable=path_loc)
    fileLocPath.grid(column=1, row=30*ttl_obj) # Assign position
    # Get file button
    # define button display text and assign the command / function
    bt_get_file_path = obj_name + '_btn'
    bt_get_file_path = ttk.Button(pa_frame, text= btn_name,
                                  command=lambda: getpath(path_loc, get_type))
    # Position Button in second row, second column (zero-based)
    bt_get_file_path.grid(column=2, row=30*ttl_obj)


# Auto popup when open
MainWin.mainloop() # Let the window keep running until close

Issue:

  1. Default file path appear in second text box only.

  2. All the button location point to second box.

I also not sure how could I get the value in different box, the "path_loc = obj_name + '_path'" not able to get the correct object.

How should I make it work? Or the way I use is wrong?

3
  • if I understand this, you want to name every widget differently in a loop and you are not able to do that, right? Commented Oct 1, 2016 at 6:23
  • Yes, since I will need to know the location for file ABC and DEF. The file picker also not work, when I press "Get ABC" it update to the text box in DEF file path. Commented Oct 1, 2016 at 7:19
  • we use dictionary (or list) for this - ie. path_loc[obj_name] = ... Commented Oct 1, 2016 at 8:12

1 Answer 1

3

Tkinter widgets are no different than any other python objects with respect to creating them in a loop. Your problem seems to be that you don't know how to create a unique variable for an unknown number of widgets.

The important thing to know is that you don't need a unique variable for each widget. Instead, you can use a list or dictionary, either of which can be easily extended at runtime.

Saving widget references in a dictionary

Here is a solution using a dictionary:

entries = {}
for key in obj2create:
    ...
    entries[key] = ttk.Entry(...)
    ...
...
print("the value for file1 is", entries["file1"].get()

Creating a custom compound widget

If you're wanting to create sets of widgets that are to be treated as a group, it may be better to create a class. In effect, you're creating your own custom widget. This type of class is often called a "compound widget" or "megawidget".

For example:

class FileWidget(ttk.Frame):
    def __init__(self, parent, name):
        ttk.Frame.__init__(self, parent)
        self.label = ttk.Label(self, text="%s Location" % name)
        self.fileLocPath = ttk.Entry(self)
        self.bt_get_file_path = ttk.Button(self, text=name, command=self.get_path)
        ...

    def get_path(self):
        return self.fileLocPath.get()

You can then create each row in your GUI like this:

widgets = {}
for key in obj2create:
    widgets[key] = FileWidget(mainFrame, key)
    widgets[key].pack(side="top", fill="x")

Later, you can get back the values like this:

for key in obj2create:
    widget = widgets[key]
    print("%s: %s" % (key, widget.get_path())
Sign up to request clarification or add additional context in comments.

1 Comment

Tks, it really work, I think this one is advance and need to take time to understand.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.