Почему функция get Tkinter Entry ничего не возвращает? - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь использовать два диалоговых окна для ручного ввода, а затем работать с этими данными.
Все найденные мной источники утверждают, что я должен использовать функцию get(), но я еще написал простую мини-программу , и я не могу заставить работать второй диалог.
Надеюсь, кто-нибудь скажет мне, что я делаю не так. Вот файл:

from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox

def getpath():
    def selectPath():
        path_ = askdirectory()
        path.set(path_)
    root = Tk()
    root.title('select path')
    path = StringVar()
    def close():
        if(path.get()==""):
            messagebox.showinfo("","nothing")
        else:
            root.withdraw()
            root.quit()
    Label(root,text="path:").grid(row=0,column=0)
    Entry(root,textvariable = path).grid(row=0,column=1)
    Button(root,text="select",command=selectPath).grid(row=0,column=2)
    Button(root,text="enter",command=close).grid(row=0,column=3)
    root.mainloop()
    return path.get()

def getname():
    def get_need_name():
        name = need_name.get()
        print('hereherehere'+name) #does not work
    root = Tk()
    root.title('select name')
    need_name = StringVar()
    Label(root,text="name:").grid(row=0,column=0)
    entry = Entry(root,bd=10,textvariable=need_name)
    entry.grid(row=0,column=1)
    Button(root,text="enter", font=16, bg="silver", relief='groove', command=get_need_name).grid(row=0,column=2)
    root.mainloop()
    return name.get()

def main():
    path = getpath()
    print("mypath:"+path)
    print('******************')
    print('done!')
    name = getname()
    print("myname:"+name)

if __name__ == '__main__':
    main()

Это дает мне два диалоговых окна, которые я могу ввести, но работает только первый диалог.

Ответы [ 2 ]

0 голосов
/ 19 июня 2020

После некоторого тестирования и поиска в Google root.quit() возникла проблема, вот рабочий пример, на который вы можете посмотреть и поиграть.

from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox

root = Tk()
path = StringVar()
def select_path():
    #uses the return value to set no need to create an additional variable
    path.set(askdirectory())
def close():
    if path.get() == "":
        messagebox.showinfo("","Please select path")
    else:
        get_name_frame.tkraise()
def get_name():
    print("hereherehere", name.get())


get_path_frame = Frame(root)
get_path_frame.grid(row=0, column=0, sticky="nsew")
Label(get_path_frame,text="path:").grid(row=0,column=0)
Entry(get_path_frame,textvariable = path).grid(row=0,column=1)
Button(get_path_frame,text="select",command=select_path).grid(row=0,column=2)
Button(get_path_frame,text="enter",command=close).grid(row=0,column=3)

get_name_frame = Frame(root)
get_name_frame.grid(row=0, column=0,sticky="nsew")
Label(get_name_frame, text="name: ").grid(row=0, column=0)
name = StringVar()
entry = Entry(get_name_frame, bd=10, textvariable = name)
entry.grid(row=0, column=1)
Button(get_name_frame,text="enter", font=16, bg="silver", relief='groove', command=get_name).grid(row=0,column=2)

get_path_frame.tkraise()
root.mainloop()


0 голосов
/ 19 июня 2020

Причина в том, что вы создаете несколько экземпляров Tk и не уничтожаете экземпляры, когда закончите с ними. Это вызывает две проблемы. Во-первых, утечка памяти. Каждый раз, когда вы вызываете одну из этих функций, вы создаете новое окно и новый интерпретатор tcl.

Вторая проблема заключается в том, что первое окно root становится окном по умолчанию, если root не указано. Когда вы создаете StringVar во второй функции, поскольку вы не указали, какому окну root оно принадлежит, оно будет назначено первому окну root. Когда вы используете его как цель textvariable во втором экземпляре Tk, tkinter думает, что переменная не существует, поэтому создает новую для второго окна. Однако ваша ссылка по-прежнему относится к тому, что создано в первом root окне, и никогда не обновляется при вводе пользователем во втором окне.

Смущает? Да, именно поэтому вам обычно не следует создавать более одного экземпляра Tk.

, чтобы ваш код работал с как можно меньшим количеством изменений и для устранения утечки памяти, вызванной не разрушением windows, вы можете изменить последние пару строк в своем методе, чтобы они выглядели следующим образом. Это разрушает окно root, когда вы закончите с ним, устраняя утечку памяти и побочный эффект наличия более одного окна root.

root = Tk()
...
root.mainloop()
value = path.get()
root.destroy()
return value

Второй диалог должен выглядеть примерно так:

root = Tk()
...
root.mainloop()
value = name.get()
root.destroy()
return value

Это извлекает значение после выхода mainloop, но до удаления базового интерпретатора tcl, а затем уничтожает окно и его tcl.

В следующий раз, когда вы создадите экземпляр Tk, этот экземпляр станет новым значением по умолчанию root, а любой новый экземпляр StringVar будет go с этим root.

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

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

...