Как создавать кнопки, текстовые поля и метки в цикле в tkinter

Я пытаюсь создать основу для создания метки, текстового поля и кнопки в качестве объекта, я могу легко расширить его.

Идея:

оригинал

после продления

и он может быть расширен до 3, 4, 5 или более, если у него будет больше файла, просто объявите в списке словаря, он будет расширен автоматически.

Код у меня есть:

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

Выпуск:

  1. Путь к файлу по умолчанию отображается только во втором текстовом поле.

  2. Расположение всех кнопок указывает на второе поле.

Я также не уверен, как я мог получить значение в другом окне, "path_loc = obj_name + '_path'" не смог получить правильный объект.

Как я должен заставить это работать? Или способ, которым я пользуюсь, неверен?

1 ответ

Решение

Виджеты Tkinter ничем не отличаются от любых других объектов Python в том, что касается их создания в цикле. Похоже, ваша проблема в том, что вы не знаете, как создать уникальную переменную для неизвестного количества виджетов.

Важно знать, что вам не нужна уникальная переменная для каждого виджета. Вместо этого вы можете использовать список или словарь, каждый из которых может быть легко расширен во время выполнения.

Сохранение ссылок на виджеты в словаре

Вот решение с использованием словаря:

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

Создание собственного составного виджета

Если вы хотите создать наборы виджетов, которые должны обрабатываться как группа, может быть лучше создать класс. По сути, вы создаете свой собственный виджет. Этот тип класса часто называют "составной виджет" или "мегавиджет".

Например:

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()

Затем вы можете создать каждую строку в вашем GUI следующим образом:

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

Позже вы можете вернуть значения следующим образом:

for key in obj2create:
    widget = widgets[key]
    print("%s: %s" % (key, widget.get_path())
Другие вопросы по тегам