как мне обновить переменную через тк окно по имени

Рассмотрим следующую ситуацию:

namespace eval ::mydialog {}

proc ::mydialog::show {w varName args} { 
   upvar 1 $varName theVar
   # now I can access theVar

   # (1)

   # code defining/creating my window
   # here some widgets for user interaction are created, 
   #   some of which will call ::mydialog::_someCallback

   wm protocol $w  WM_DELETE_WINDOW [list ::mydialog::close $w]
}

proc ::mydialog::_someCallback {}  {
   # how do I access theVar here?

   # (2)
}

proc ::mydialog::close { w } {
   # here some changes are supposed to be written back into varName in the calling scope,
   #    how do I do that?!

   # (3)

   destroy $w
}

Я пытаюсь выяснить, как (а) получить переменную из области вызова (б) сделать ее доступной во всех трех процессах и (в) записать любые изменения обратно в указанную переменную.

(a) Обычно я решаю, используя 'upvar 1 $varName theVar' (b) Обычно я решаю с помощью переменной пространства имен (c) Пока у нас есть только один процесс, который будет происходить автоматически с (a) из-за того, что мы будем работать над локальным псевдонимом этой переменной

Проблема в том, что upvar работает (по крайней мере, как задумано) только в (1). Я мог бы использовать upvar в (1) и сохранить/скопировать в переменную пространства имен, что решит (a) и (b), но не (c).

Я был бы признателен, если бы кто-то мог указать мне в правильном направлении здесь.

Кроме того, поскольку я относительно новичок в Tcl/Tk, моя концепция может быть не идеальной, поэтому предложения по улучшению дизайна также приветствуются.


person PeterE    schedule 18.08.2014    source источник
comment
Я не совсем уверен, что вы пытаетесь сделать, но вы можете вызвать процедуру с помощью theVar и использовать return в конце процедуры, чтобы получить theVar с изменениями или без них. Может быть, вы могли бы поместить небольшой воспроизводимый фрагмент того, что вы хотите получить, возможно, с некоторыми puts здесь и там (например, до и после вызова разных процессов) и сказать, что вы ожидали получить.   -  person Jerry    schedule 18.08.2014
comment
@Jerry Передача VAr в качестве параметра и возврат его с возвратом будет работать для «обычных» процедур. Но не какой диалог/окно tk между ними. Проблема в том, что ::mydialog::show не имеет прямого отношения/отношения к функции обратного вызова (например, для нажатия кнопки), в которой предполагается установить новое значение. Как указал Худикроу, можно использовать глобальное пространство имен в качестве точки отсчета, чтобы связать их вместе. Я не уверен, что мне это нравится (с точки зрения дизайна), но я не вижу другого пути.   -  person PeterE    schedule 18.08.2014


Ответы (1)


Я предлагаю вам использовать переменную пространства имен, в которой хранится имя переменной, и upvar использовать глобальную область видимости.

namespace eval ::mydialog {
    variable varName
}

proc ::mydialog::show {w _varName args} { 
    variable varName $_varName
    upvar #0 $varName theVar

}

proc ::mydialog::_someCallback {}  {
    variable varName
    upvar #0 $varName theVar
    puts $theVar
}

proc ::mydialog::close { w } {
    variable varName
    upvar #0 $varName theVar
    set theVar newval
}

set globalvar oldval
# => oldval
::mydialog::show {} globalvar
::mydialog::_someCallback
# => oldval
::mydialog::close {}
# => newval
puts $globalvar
# => newval

Обратите внимание, что подсветка синтаксиса не работает: #0 $varName theVar на самом деле не является комментарием.

Это работает и с переменными пространства имен: если у вас есть переменная с именем nsvar в пространстве имен ::foobar, вы можете использовать ее следующим образом:

set ::foobar::nsvar oldval
::mydialog::show {} ::foobar::nsvar
::mydialog::_someCallback
::mydialog::close {}
puts $::foobar::nsvar

с теми же эффектами.

Однако таким образом нельзя использовать локальные переменные для какой-либо процедуры.

Один из способов сделать это действительно простым — использовать виджеты Snit вместо коллекций процедур Tcl.

Документация: пространство имен, proc, помещает, набор, upvar, переменная

Документация Snit: справочная страница, faq (часто задаваемые вопросы также служат своего рода введением)

person Peter Lewerin    schedule 18.08.2014
comment
Я думаю, что ваш последний пункт (однако вы не можете использовать локальные переменные для какой-либо процедуры таким образом.) - это то, на что я наткнулся. Если я правильно вас понимаю, я должен использовать полностью определенные varNames или вставлять их все в глобальное пространство имен :-( на мой взгляд, не совсем хороший стиль. Я пытался использовать upvar с относительными уровнями, которые не работали из-за магии обратного вызова практикуется tk (по-видимому, обратные вызовы tk всегда имеют уровень #2 и не имеют отношения к области, в которой они определены; что, оглядываясь назад, имеет смысл) - person PeterE; 18.08.2014
comment
@Peter: здесь вам, вероятно, следует использовать переменные пространства имен. В этом случае вы можете сделать вызовы немного менее болезненными, зарегистрировав пространство имен и имя переменной отдельно и используя namespace upvar вместо обычного upvar. В противном случае да, так оно и есть. Однако это не ошибка, а следствие того, как работает система виджетов. См. мой добавленный комментарий о Snit. - person Peter Lewerin; 18.08.2014