Как получить StringVar (не текстовое значение, а сам StringVar) записи?

Я пытаюсь связать объект 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'>

В настоящее время tkinter не поддерживает поиск ссылки на переменную по внутреннему имени. Вам необходимо создать словарь для хранения внутреннего имени для сопоставлений переменных.

acw1668 29.05.2024 03:36

@acw1668 acw1668 как насчет моего решения ниже?

Danya K 29.05.2024 03:44

@DanyaK На самом деле ваше решение не касается вопроса ОП.

acw1668 29.05.2024 03:45

@ acw1668 acw1668 Я думаю, что мое решение охватывает большую часть вопроса ОП, хотя я не уверен насчет его последнего предложения.

Danya K 29.05.2024 03:56

В частности, что касается последней части, если вы создаете запись и не устанавливаете текстовую переменную, она создает ее неявно. Проблема в том, что у него нет названия. Под этим я имею в виду, что использование входной записи["текстовая переменная"] или вход.cget("текстовая переменная") возвращает пустую строку. Если в этом случае невозможно получить StringVar, я мог бы заставить ваш ответ работать, но я бы предпочел другое решение.

Choosechee 29.05.2024 05:31

Я думаю, что если вы не установили variable для Entry, то textvariable у него вообще не будет. Он не создаст его автоматически. Как вы думаете, почему он создаст это неявно, откуда вы взяли эту информацию?

Danya K 29.05.2024 05:43

Мне кажется, вы это слишком усложняете. Если вы хотите получить текст от Entry, используйте entry.get() без использования StringVar.

furas 29.05.2024 13:57

если вам действительно нужно использовать StringVar, сохраните его в каком-нибудь списке или словаре - поставьте лайк data = {entry: variable) и используйте data[entry].get(). Или вы можете назначить StringVar другому классу, например entry.variable = StringVar()

furas 29.05.2024 14:00

Я думаю, проблема в том, что tkinter — это оболочка модуля tk, созданная на языке tcl, который имеет свои собственные правила и tkinter пытается их воссоздать.

furas 29.05.2024 14:10

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

furas 29.05.2024 14:13

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

Choosechee 29.05.2024 16:53
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
11
88
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы знаете имя переменной, вы можете просто «создать» 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 29.05.2024 09:17

@acw1668 acw1668 да, в этом ты прав. Это то, что вы имели в виду в комментарии к вопросу ОП: вы не можете найти реальный экземпляр stringVar, используя этот метод?

Danya K 29.05.2024 14:15

Я только что попробовал это, и полученная мной StringVar имеет правильное содержимое, но она не работает для добавления прослушивателя к содержимому записи. Я использую входContents_trace_add("write", functionName), но он никогда не запускается при записи в запись. Он запускается только в том случае, если я редактирую его напрямую. с помощью набора.

Choosechee 29.05.2024 22:11

@Choosechee trace_add у меня работает, возможно, ты допустил ошибку

Danya K 29.05.2024 22:32

Мне кажется, вы это слишком усложняете.

Если вы хотите получить текст от 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, о котором можно легко забыть.

Danya K 29.05.2024 14:22

как по мне, вы все усложняете. Установка новой текстовой переменной — очень и очень необычная ситуация. Так что я бы не стал заморачиваться. Вы всегда можете создать собственный класс, который автоматически создает StringVar, и добавить функцию для замены текстовой переменной (и не разрешать назначать ее напрямую. Но если вы хотите получить текст, используйте entry.get() без StringVar - и проблема с textvariable будет решена. И если вам действительно нужен StringVar, то лучше опишите (в вопросе), зачем вам это нужно, потому что, возможно, есть лучшее решение.

furas 29.05.2024 14:50

Кстати: если вам нужно изменить textvariable, то, вероятно, у вас что-то не так в логике кода.

furas 29.05.2024 14:53

Вы правы, я люблю все усложнять. Обычно я всегда стараюсь подумать обо всем, что может пойти не так. И я знаю, что такой ситуации, скорее всего, не произойдет, но кто знает. Может возникнуть ситуация, когда вам нужно измениться textvariable. Но я полностью согласен с вашим комментарием, что настоящий StringVar экземпляр вам никогда не понадобится.

Danya K 29.05.2024 14:58

возможно, вам следует попытаться создать собственный класс Entry, скрыть прямой доступ к textvariable и добавить функцию set_textvariable, которая автоматически назначит ее entry.my_variable. И, возможно, это хорошая (сложная) задача для вас ;) И когда вы создадите этот класс, вы сможете поставить его в качестве ответа. Возможно, это будет полезно другим пользователям.

furas 29.05.2024 15:10

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

Danya K 29.05.2024 15:20

Другие вопросы по теме