Как мне сохранить поля динамического ввода заполненными после завершения работы функции, которая их создала?

#python-2.7 #tkinter #ttk

#python-2.7 #tkinter #ttk

Вопрос:

Я работаю над графическим интерфейсом для автоматизации части конвейера моего проекта с использованием Tkinter и ttk в Python 2.7. У меня есть главное окно Tk (), которое генерирует окно Toplevel () при нажатии «Автоопределение», затем создает динамическую серию виджетов ввода только для чтения при нажатии кнопки на основе списка молекулярных видов, определенных в другом месте кода.

Моя проблема в том, что, хотя поля ввода отображаются правильно на основе обнаруженных видов, они не остаются заполненными названиями видов после завершения работы функции, которая их создала. Я подозреваю, что это связано с тем, что виджеты не являются глобальными [или даже в пределах окна Tk ()], а скорее определены только внутри функции. Однако я не могу создать их в блоке кода, где определено окно Tk (), поскольку количество необходимых полей ввода неизвестно до тех пор, пока не будет нажата кнопка (таким образом, вызывается функция, которая их создает).

Ниже я включил абстрактный блок кода, который показывает проблему, с которой я столкнулся. Прошу прощения, если это длинно. Я попытался максимально сократить это. Комментарии, которые я включил в код, показывают мои мысли и догадки о том, что происходит. Он должен быть готов к запуску в Python 2.7; я надеюсь, что единственными необходимыми изменениями в Python 3.x являются модификации импорта.

Мой вопрос в том, что после того, как я динамически создал виджеты ввода в функции, вызываемой главным окном Tk (), и заполнил их текстом, как я могу предотвратить их исчезновение при завершении функции?Отказ от ответственности: Я не программист (или даже не специалист в области компьютерных наук) по профессии, поэтому я сделаю все возможное, чтобы придерживаться всех технических деталей, но, возможно, мне придется задать несколько глупых вопросов.

 from Tkinter import *
import ttk
from  time import sleep

def update_list(manager, rows):
    species_list = ['A','B','C','D']
    del rows[1:]

    for widget in manager.children.values():
        widget.grid_forget()
    if not species_list == ['']:
        species_elem_list = []
        for i, each in enumerate(species_list):

            ## Here I attempt to create a dynamic list of StringVars to attach to the Entry fields below, based on the contents of the species list.
            species_elem_list.append(StringVar())

            ## Here I initialize the values of the elements of the Entry fields by setting the StringVar of each.
            species_elem_list[i].set(each)

            ## I tried to attach the value of the StringVar (from the species list) to the Entry below, but when the program is run, the Entry does not stay populated.
            temp_name = ttk.Entry(manager, textvariable=species_elem_list[i], state='readonly')
            temp_color = ttk.Label(manager, text='data')
            temp_row = [temp_name, temp_color]
            rows.append(temp_row)

        for row_number in range(len(rows)):
            for column_number, each in enumerate(rows[row_number]):
                each.grid(column=column_number, row=row_number)
            each.grid()

        manager.update()
        sleep(3) ## Included so that the population of the fields can be observed before they depopulate.

        ## After this point, the update_list function terminates.
        ## When that happens, the Entry fields depopulate. How can I get them to persist after the function terminates?

root = Tk()

manager = ttk.Frame(root, padding='4 5 4 4')
manager.grid(column=0, row=0, sticky=NSEW)

name_label = ttk.Label(manager, text='Name')
color_label = ttk.Label(manager, text='RGB')

rows = [[name_label, color_label]]

options = ttk.Frame(root)
options.grid(sticky=NSEW)

detect_button = ttk.Button(options, text='Auto-Detect', command=lambda: update_list(manager,rows))
done_button = ttk.Button(options, text='Done', command=root.destroy)

detect_button.grid(column=0, row=0)
done_button.grid(column=1, row=0)

root.mainloop()
  

В идеале, виджеты ввода останутся (и останутся заполненными!) после завершения работы функции update_list. Я также хочу иметь возможность взаимодействовать с содержимым этих виджетов извне функции.

В настоящее время поля ввода заполняются в ходе выполнения функции update_list, а затем сразу же удаляются после ее завершения. Я подозреваю, что это связано с тем, что виджеты и их содержимое не являются глобальными по объему.

Комментарии:

1. textvariable=species_elem_list вы используете локальную переменную species_elem_list , которая перестает существовать при выходе update_list

Ответ №1:

В textvariable=species_elem_list вы используете локальную переменную species_elem_list , которая перестает существовать при выходе update_list()

Вы должны создать species_elem_list outside update_list() и использовать global species_elem_list in update_list() , чтобы использовать глобальную переменную вместо локальной, когда вы делаете species_elem_list = []

 from Tkinter import *
import ttk
from  time import sleep

species_elem_list = [] # <--- put here or below of update_list

def update_list(manager, rows):
    global species_elem_list  # <-- use global variable instead of local one

    species_list = ['A','B','C','D']

    del rows[1:]

    for widget in manager.children.values():
        widget.grid_forget()

    if not species_list == ['']:
        species_elem_list = []
        for i, each in enumerate(species_list):

            ## Here I attempt to create a dynamic list of StringVars to attach to the Entry fields below, based on the contents of the species list.
            species_elem_list.append(StringVar())

            ## Here I initialize the values of the elements of the Entry fields by setting the StringVar of each.
            species_elem_list[i].set(each)

            ## I tried to attach the value of the StringVar (from the species list) to the Entry below, but when the program is run, the Entry does not stay populated.
            temp_name = ttk.Entry(manager, textvariable=species_elem_list[i], state='readonly')
            temp_color = ttk.Label(manager, text='data')
            temp_row = [temp_name, temp_color]
            rows.append(temp_row)

        for row_number in range(len(rows)):
            for column_number, each in enumerate(rows[row_number]):
                each.grid(column=column_number, row=row_number)
            each.grid()

        manager.update()
        sleep(3) ## Included so that the population of the fields can be observed before they depopulate.

        ## After this point, the update_list function terminates.
        ## When that happens, the Entry fields depopulate. How can I get them to persist after the function terminates?

root = Tk()

manager = ttk.Frame(root, padding='4 5 4 4')
manager.grid(column=0, row=0, sticky=NSEW)

name_label = ttk.Label(manager, text='Name')
color_label = ttk.Label(manager, text='RGB')

rows = [[name_label, color_label]]

options = ttk.Frame(root)
options.grid(sticky=NSEW)

detect_button = ttk.Button(options, text='Auto-Detect', command=lambda: update_list(manager,rows))
done_button = ttk.Button(options, text='Done', command=root.destroy)

detect_button.grid(column=0, row=0)
done_button.grid(column=1, row=0)

root.mainloop()