2013-05-24 2 views
1

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

Затем появляется всплывающее окно и спрашивает, хотите ли вы выбрать другой файл. Каждый выбранный файл должен перейти в массив.

Я должен следующий код:

########## Defining the sub procedures ############ 
proc open_file {} { 
    set n 0 
    set title "Select a file" 
    set types { 
     {{GDS files} {.gds} } 
     {{All Files} * } 
    } 

    set filename [tk_getOpenFile -filetypes $types -title $title] 

    set opendFiles($n) $filename 
    set n [expr $n + 1] 

    set answer [tk_messageBox -message "Load another GDS file?" -type yesno -icon question] 
    if {$answer == yes } { 
     open_file 
    } else { 
     show_files ($opendFiles) 
    } 
} 

proc show_files {} { 
    foreach key [array names opendFiles] { 
     puts $opendFiles($key) 
    } 
} 

########## Main Program ########### 
open_file 

меня возникают следующие проблемы. Потому что я всегда вспоминаю proc 'open_file' переменная $n сохраняет значение 0. Но я не знаю, как вспомнить открытие окна, не обращая внимания на всю подпрограмму.

Вторая проблема заключается в отправке массива в следующую процедуру. Когда я отправляю в proc 'show_files', я всегда получаю следующую ошибку: can't read "opendFiles": variable is array.

Я не могу найти как ответы ..

+0

set/init 'n' вне proc. в proc используйте 'incr :: n', чтобы увеличить значение. ':: n' - глобальная переменная. – alexvetter

+0

для отправки массива в другой proc используйте 'array get' &' array set' – alexvetter

+0

или передайте имя переменной и используйте 'upvar' –

ответ

1

Вам нужны глобальные переменные для этого. Это работает для меня:

########## Defining the sub procedures ############ 
set n 0 
array set openedFiles {} 

proc open_file {} { 
    set title "Select a file" 
    set types { 
     {{GDS files} {.gds} } 
     {{All Files} * } 
    } 

    set filename [tk_getOpenFile -filetypes $types -title $title] 

    set ::openedFiles($::n) $filename 
    incr ::n 

    set answer [tk_messageBox -message "Load another GDS file?" -type yesno -icon question] 
    if {$answer == yes } { 
     open_file 
    } else { 
     show_files 
    } 
} 

proc show_files {} { 
    foreach key [array names ::openedFiles] { 
     puts $::openedFiles($key) 
    } 
} 

########## Main Program ########### 
open_file 

Массив Проблема

В Tcl вы не можете отправить массивы проки. Вам нужно преобразовать их в список с array get, чтобы отправить этот список в proc и затем преобразовать его обратно в массив снова с array set.

+0

Это сработало для меня! Спасибо за вашу помощь! –

+0

Надеюсь, вы не скопировали и не ввели код! :-) Если вы хотите это узнать, вам нужно написать и понять. :-P – alexvetter

+0

Я набрал код в свою программу. Я получаю свои ошибки сейчас, все еще нужно много узнать, я знаю;) –

1

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

Кроме того, где вы будете использовать массив в других языках программирования, часто лучше использовать список в Tcl, так что-то вроде:

proc open_file {} { 
    set title "Select a file" 
    set types { 
     {{GDS files} {.gds} } 
     {{All Files} * } 
    } 

    set filename [tk_getOpenFile -filetypes $types -title $title] 
    return $filename 
} 

proc show_files {files} { 
    foreach file $files { 
     puts $file 
    } 
} 

set openedFiles [list] 
set answer yes 

while {$answer == yes} 
    lappend openedFiles [open_file] 
    set answer [tk_messageBox -message "Load another GDS file?" -type yesno -icon question] 
} 
show_files $openedFiles 

Если вы в краткости, show_files может быть записано

proc show_files {files} { 
    puts [join $files \n] 
} 

и, теперь, когда это так коротко, вы можете просто положить его в линию, а не иметь еще один прок.

И, наконец, вы считали, что хотите, если пользователь нажимает на отмену в tk_getOpenFile? В этом случае имя файла будет установлено в пустую (нулевую) строку. Вы можете либо

  • игнорировать эти; или
  • избавиться от вызова tk_messageBox и нажать на кнопку отменить, когда они ввели столько файлов, сколько захотят.

Если вы хотите просто игнорировать те времена, когда пользователь нажал отменить, вы могли бы сделать

set filename [open_file] 
if {[string length $filename] > 0} { 
    # The user entered a new filesname - add it to the list 
    lappend openedFiles $filesname 
} else { 
    # The user pressed cancel - just ignore the filename 
} 

Если вы хотите использовать отменить, чтобы выйти из цикла, то основная программа становится чем-то вроде :

set openedFiles [list] 
set filename dummy 
while {[string length $filename] > 0} { 
    set filename [open_file] 
    if {[string length $filename] > 0} { 
     lappend openedFiles $filename 
    } 
} 
show_files $openedFiles 

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

0

Для того чтобы состояние переменной сохранялось между вызовами процедуры, вам необходимо сделать эту переменную вне процедуры. Самый простой способ состоит в использовании глобальной переменной:

# Initialize it... 
set n 0 
proc open_file {} { 
    # Import it... 
    global n 
    ... 
    # Use it... 
    set openedFiles($n) $filename 
    incr n 
    ... 
} 

Массивы не являются значениями, и как таковые не могут быть переданы непосредственно к другой процедуре. Вы не можете справиться с этим, передавая имя и используя upvar 1 связать локальный псевдоним переменной в вызывающем кадре стека:

proc show_files {varName} { 
    upvar 1 $varName ary 
    foreach key [array names ary] { 
     puts $ary($key) 
    } 
} 

который называется использованием имя массива, так что не $:

show_files openedFiles 

(Вы можете также передать сериализации массива с использованием array get openedFiles сериализовать и array set ary $serialization десериализации, но это несет некоторые накладные расходы.)

Вероятно, вы должны добавить переменную openedFiles в строку global, чтобы она была постоянной по всем вызовам open_file.

Смежные вопросы