Я пытаюсь связать объект StringVar с виджетом Entry, но не могу понять, как это сделать.
Я нашел этот вопрос: привязать StringVar к виджету Entry но ни один из ответов не работает для меня. И запись["textvariable"] и вход.cget("textvariable") возвращают имя StringVar, а не сам StringVar (хотя ответ со вторым объясняет это правильно, в отличие от ответа с первым, который НЕ ясно, что это возвращает только имя. Я внес первое изменение, которое это исправляет). Предполагается, что вы сможете получить StringVar из его имени, используя вход.getvar(name), но при этом возвращается строка с содержимым StringVar вместо самого StringVar. Я не понимаю, почему это происходит, потому что ответ, объясняющий это, помечен как правильный, и человек, задавший вопрос, похоже, хотел сам StringVar. Что-то изменилось? Если да, то как мне теперь получить StringVar? Сейчас я использую Python 3.11.9. Я также предпочел бы метод, которому не требуется имя StringVar, поскольку запись без явно установленного StringVar, похоже, имеет StringVar без имени.
Вот пример кода:
from tkinter import *
from tkinter.ttk import *
root = Tk()
stringVar = StringVar(root, "test") # obviously in the real program I wouldn't be able to access this without using the Entry
entry = Entry(root, textvariable=stringVar)
entry.pack()
name1 = entry["textvariable"]
name2 = entry.cget("textvariable")
print(name1 == name2) # True
shouldBeStringVar = entry.getvar(name1)
print(name1, type(name1)) # PY_VAR0 <class 'str'>
print(shouldBeStringVar, type(shouldBeStringVar)) # test <class 'str'>
@acw1668 acw1668 как насчет моего решения ниже?
@DanyaK На самом деле ваше решение не касается вопроса ОП.
@ acw1668 acw1668 Я думаю, что мое решение охватывает большую часть вопроса ОП, хотя я не уверен насчет его последнего предложения.
В частности, что касается последней части, если вы создаете запись и не устанавливаете текстовую переменную, она создает ее неявно. Проблема в том, что у него нет названия. Под этим я имею в виду, что использование входной записи["текстовая переменная"] или вход.cget("текстовая переменная") возвращает пустую строку. Если в этом случае невозможно получить StringVar, я мог бы заставить ваш ответ работать, но я бы предпочел другое решение.
Я думаю, что если вы не установили variable для Entry, то textvariable у него вообще не будет. Он не создаст его автоматически. Как вы думаете, почему он создаст это неявно, откуда вы взяли эту информацию?
Мне кажется, вы это слишком усложняете. Если вы хотите получить текст от Entry, используйте entry.get() без использования StringVar.
если вам действительно нужно использовать StringVar, сохраните его в каком-нибудь списке или словаре - поставьте лайк data = {entry: variable) и используйте data[entry].get(). Или вы можете назначить StringVar другому классу, например entry.variable = StringVar()
Я думаю, проблема в том, что tkinter — это оболочка модуля tk, созданная на языке tcl, который имеет свои собственные правила и tkinter пытается их воссоздать.
главный вопрос - зачем это нужно? Возможно, ваша реальная проблема другая и, возможно, есть лучшее решение вашей реальной проблемы.
Извините, я просто предположил, что для работы Entry требуется StringVar, поэтому он создаст его, если он не будет предоставлен. Я пытался добавить прослушиватель к содержимому записи. Я знаю, что есть проверка, но она не подходит для моего варианта использования.






Если вы знаете имя переменной, вы можете просто «создать» StringVar и установить для ее параметра «имя» это имя. Таким образом, вы просто получите созданную ранее переменную. Итак, попробуйте следующее:
...
string_name = entry["textvariable"]
TheVarObjectYouNeed = var = tk.StringVar(name=string_name)
print(f"The var {var} has a type {type(var)}, just as you wanted")
print(f'And it has the value "{var.get()}"')
...
Обратите внимание, что этот код фактически создает новый объект StringVar. Но поскольку я установил существующее имя, «TheVarObjectYouNeed» фактически будет ссылаться на ту же внутреннюю переменную внутри основного интерпретатора TCL (как правильно указано в комментарии ниже), та же переменная TCL используется для вашего виджета Entry.
Это создает новый экземпляр StringVar, который ссылается на ту же внутреннюю переменную внутри базового интерпретатора TCL, потому что id(stringVar) (stringVar — исходный экземпляр в вопросе OP) не совпадает с id(var).
@acw1668 acw1668 да, в этом ты прав. Это то, что вы имели в виду в комментарии к вопросу ОП: вы не можете найти реальный экземпляр stringVar, используя этот метод?
Я только что попробовал это, и полученная мной StringVar имеет правильное содержимое, но она не работает для добавления прослушивателя к содержимому записи. Я использую входContents_trace_add("write", functionName), но он никогда не запускается при записи в запись. Он запускается только в том случае, если я редактирую его напрямую. с помощью набора.
@Choosechee trace_add у меня работает, возможно, ты допустил ошибку
Мне кажется, вы это слишком усложняете.
Если вы хотите получить текст от Entry, используйте entry.get() без использования StringVar
Если вам действительно нужен объект StringVar, вы можете назначить его непосредственно Entry (или любому другому классу).
entry.my_variable = stringVar
и позже вы сможете получить к нему доступ с помощью entry.my_variable
stringVar = StringVar(root, "test")
entry = Entry(root, textvariable=stringVar)
entry.my_variable = stringVar # <---
entry.pack()
В конце концов вы можете создать собственный класс, который будет делать это автоматически.
Это неплохая идея, но что, если вы позже измените свой textvariable на что-то другое (чего, скорее всего, не произойдет, но все же можно сделать)? В этом случае вам также нужно будет не забыть изменить его на my_variable, о котором можно легко забыть.
как по мне, вы все усложняете. Установка новой текстовой переменной — очень и очень необычная ситуация. Так что я бы не стал заморачиваться. Вы всегда можете создать собственный класс, который автоматически создает StringVar, и добавить функцию для замены текстовой переменной (и не разрешать назначать ее напрямую. Но если вы хотите получить текст, используйте entry.get() без StringVar - и проблема с textvariable будет решена. И если вам действительно нужен StringVar, то лучше опишите (в вопросе), зачем вам это нужно, потому что, возможно, есть лучшее решение.
Кстати: если вам нужно изменить textvariable, то, вероятно, у вас что-то не так в логике кода.
Вы правы, я люблю все усложнять. Обычно я всегда стараюсь подумать обо всем, что может пойти не так. И я знаю, что такой ситуации, скорее всего, не произойдет, но кто знает. Может возникнуть ситуация, когда вам нужно измениться textvariable. Но я полностью согласен с вашим комментарием, что настоящий StringVar экземпляр вам никогда не понадобится.
возможно, вам следует попытаться создать собственный класс Entry, скрыть прямой доступ к textvariable и добавить функцию set_textvariable, которая автоматически назначит ее entry.my_variable. И, возможно, это хорошая (сложная) задача для вас ;) И когда вы создадите этот класс, вы сможете поставить его в качестве ответа. Возможно, это будет полезно другим пользователям.
Я не вижу смысла писать новый класс. Как вы сказали, и я согласился, на самом деле нет никаких обстоятельств, при которых вам нужно было бы получить экземпляр StringVar.
В настоящее время
tkinterне поддерживает поиск ссылки на переменную по внутреннему имени. Вам необходимо создать словарь для хранения внутреннего имени для сопоставлений переменных.