Tcl/Tk — как получить приглашение после выполнения команды с помощью eval?

Код для воспроизведения моей проблемы приведен ниже. Я назвал файл как test.tcl

#-------------------------------------------------------------------
# test.tcl
#-------------------------------------------------------------------

namespace eval Gui {
}

proc Gui::test {} {
  toplevel .test
  wm title .test "Test"
  wm resizable .test 0 0 ;# not resizable

  # create a frame to hold the check widgets
  set f [frame .test.boolean -borderwidth 10] 
  pack $f -side top

  # OK and Cancel buttons
  button .test.ok -text "OK" -command [list Gui::Ok .test ]
  button .test.cancel -text "Cancel" -command [list Gui::cancel .test ]
  pack   .test.cancel .test.ok -side right

  bind .test <Return> {Gui::Ok .test ; break}
  bind .test <Escape> {Gui::cancel .test ; break}
}

proc Gui::Ok { arg } {
  set x [list puts "hello world!"]
  eval $x
  destroy $arg
}

proc Gui::cancel { arg } {
  destroy $arg
}

#-------------------------------------------------------------------
# Gui main window 
#-------------------------------------------------------------------
proc Gui::initialize { } {

  # build the frame which contains menu options
  frame .mbar -relief raised -bd 2
  frame .mdummy -width 200 -height 240
  pack .mbar .mdummy -side top -fill x

  # menu options
  menubutton .mbar.command -text Command -underline 0 -menu .mbar.command.menu
  pack .mbar.command -side left

  # menu under command options
  menu .mbar.command.menu -tearoff 0
  .mbar.command.menu add command -label "Test..." -command [list Gui::test]
}

#-------------------------------------------------------------------
# main code
#-------------------------------------------------------------------
Gui::initialize

Когда я печатаю

% wish
% source test.tcl
%

а затем я нажимаю Command -> Test ... -> OK, что дает мне

% hello world!

Я не получаю подсказку % после того, как она напечатает hello world!. Хотя я все еще могу выполнять команды tcl в этом пространстве. Например:

% hello world!
puts "hi"
hi
%

который возвращает подсказку.

Мой вопрос: как вернуть подсказку % после того, как tcl/tk выполнит команду eval, которая напечатает hello world!


person Anand    schedule 22.04.2011    source источник


Ответы (2)


Приглашение % пришло от интерпретатора tcl и показано в терминале только потому, что оно находится в интерактивном режиме. Если вы запустите свой скрипт как wish test.tcl, вы никогда не получите %.

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

proc Gui::interactive {} {
  set prompt1 "tcl>"
  set prompt2 "?"
  set cmd {}
  set prompt "$prompt1 "
  fconfigure stdin -blocking false -buffering line
  fileevent stdin readable {set Gui::stdinReady 1}
  while true {
    puts -nonewline $prompt
    flush stdout
    vwait Gui::stdinReady
    set str [gets stdin]
    lappend cmd $str
    set cmdStr [join $cmd "\n"]
    if {[info complete $cmdStr]} {
      set cmd {}
      if {$cmdStr != ""} {
        if {[catch {eval $cmdStr} result]} {
          puts stderr "ERROR: $result"
        } elseif {$result != ""} {
          puts $result
        }
      }
      set prompt "$prompt1 "
    } else {
      set prompt "$prompt2 "
    }
    if {[eof stdin]} {
      puts ""
      break
    }
  }
}

Просто вызовите эту функцию после Gui::test выполнения, и вы получите собственное приглашение. Но даже в этом примере подсказка не будет перерисована, если текст будет напечатан на терминал из какой-то другой процедуры.

person GrAnd    schedule 22.04.2011
comment
Спасибо. Я попробую это и дам вам знать - person Anand; 22.04.2011
comment
Мне удалось вызвать Gui::interactive из Gui::test, и когда я выполняю Command -> Test ... -> OK, подсказка отображается как tcl>; Но когда я что-то набираю в tclsh, я получаю подсказку % tcl> Любое предложение избавиться от лишних % в % tcl>? - person Anand; 23.04.2011
comment
Только не выполняйте tcl в интерактивном режиме. Выполнить как wish your_script.tcl. - person GrAnd; 23.04.2011

Вы никогда не теряли подсказку %. Вот что происходит:

У вас есть подсказка:

%

Затем вы печатаете строку в той же строке:

% hello world!

Ваша «текущая» подсказка по-прежнему такая же. Следующая команда включена в этом приглашении:

puts "hi"

Который, поскольку он работает в tclsh и поскольку вы только что вставили новую строку, появляется на следующей строке:

hi

И вы получаете еще одну подсказку:

%

Вы не получили «другое» приглашение от своего графического интерфейса, потому что puts "hello world" не обрабатывалось tclsh напрямую. По сути, что касается tclsh, «привет, мир» пришел с Марса и испортил ваш терминал. Он даже не знает, что там.

Может быть, лучше объяснить это следующим образом: если бы ваш puts "hello world" печатал в файл, то у вас все еще было бы приглашение %. Но кто-то взял эти символы и поместил их на ваш дисплей (включая новую строку).

person drysdam    schedule 22.04.2011
comment
В этом есть смысл. Есть ли способ связаться с tclsh напрямую? - person Anand; 22.04.2011
comment
Я не могу придумать способ обновить экран терминала из программы, нет. Но почему вы все равно должны работать в tclsh напрямую? - person drysdam; 22.04.2011
comment
+1 за хорошее объяснение. Tclsh не выполняет специальной привязки к терминалу, поэтому обнаружение таких вещей, как Ctrl+R (традиционная последовательность обновления терминала), не происходит, и приглашение остается нераспечатанным. Вы всегда можете попробовать использовать tkcon в качестве альтернативы, но это совершенно другой подход (графическое приложение выполняет некоторую эмуляцию терминала, а не полную обработку терминала). - person Donal Fellows; 22.04.2011
comment
Я разрабатываю приложение, в котором пользователь может использовать как tclsh, так и графический интерфейс, а также смешивать их; Вот почему мне нужна подсказка. - person Anand; 22.04.2011
comment
Тогда я думаю, вам нужна идея GrAnd о реализации вашей собственной оболочки tclsh, которая может знать, когда вы печатаете результаты из графического интерфейса. Кроме того, вы можете распечатать результаты GUI в другом месте. - person drysdam; 22.04.2011