Как мне заполнить динамические поля ввода после завершения функции, которая их создала? - PullRequest
0 голосов
/ 07 апреля 2019

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

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

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

Мой вопрос заключается в том, что после того, как я динамически создал виджеты Entry внутри функции, которая вызывается из главного окна 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()

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

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

1 Ответ

0 голосов
/ 07 апреля 2019

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

Вы должны создать species_elem_list вне update_list() и использовать global species_elem_list в 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()
...