Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Trouble with .entry text refeshing

Status
Not open for further replies.

SloppyNick

Programmer
Jun 11, 2007
6
US
I am trying to write a virtual console that will allow the user to run programs from tcl/tk. The purpose is so the user can manupilate command-line parameters with check boxes so they don't have to retype them each time they want to change something. Here is my code:
Code:
#!/usr/bin/wish
# execlog - run a program with exec and log the output
# Set window title
wm title . ExecLog

# Create a frame for buttons and entry.
frame .top -borderwidth 10
pack .top -side top -fill x

# Create the command buttons.
button .top.quit -text Quit -command exit
set clear_button [button .top.clear -text Clear -command Clear]
set but [button .top.run -text "Run it" -command Run]
pack .top.quit .top.clear .top.run -side right

# Create a labeled entry for the command
label .top.l -text Command: -padx 0
entry .top.cmd -width 20 -relief sunken \
  -textvariable command
pack .top.l -side left
pack .top.cmd -side left -fill x -expand true

# Set up key binding equivalents to the buttons
bind .top.cmd <Return> Run
bind .top.cmd <Control-c> Stop
focus .top.cmd

# Create a text widget to log the output
frame .t
set log [text .t.log -width 80 -height 10 \
  -borderwidth 2 -relief raised -setgrid true \
  -yscrollcommand {.t.scroll set}]
scrollbar .t.scroll -command {.t.log yview}
pack .t.scroll -side right -fill y
pack .t.log -side left -fill both -expand true
pack .t -side top -fill both -expand true

# Run the program and arrange to read its input
proc Run {} {
  global command input log but
  if [catch {open "|$command |& cat"} input] {
    $log insert end $input\n
  } else {
    fileevent $input readable Log
    $log insert end $command\n
    $but config -text Stop -command Stop
  }
}

# Read and log output from the program
proc Log {} {
  global input log
  if [eof $input] {
    Stop
  } else {
    gets $input line
    $log insert end $line\n
    $log see end
  }
#  update
}

# Stop the program and fix up the button
proc Stop {} {
  global input but
  catch {close $input}
  $but config -text "Run it" -command Run
}

proc Clear {} {

}

My problem is that the entry doesn't refresh (ie, display the output of the program) until the program is stopped, or the entry is double-clicked. Is there any way to force the entry to refresh itself?

I tried adding an update call to the callback Proc, but the nested calls cause an infinite loop error.

Any other ideas?
 
Just to be clear, you're displaying the program output in the text widget, .t.log, not the entry widget, right?

I don't see where you might be entering an infinite loop. What happens if you let the program run? Does it terminate normally?

What is it you expect to see in .t.log before the program ends? That is are you expecting $command\n, or $line\n? If the former, you should switch the order of the lines fileevent $input readable Log and $log insert end $command\n


_________________
Bob Rashkin
 
Excuse me, you are correct, I am using a text widget.

When I call update in the Proc, I don't technically have an infinite loop, but I get an infinite loop error. I'm assuming that tcl is fooled into thinking there is an infinite loop because the fileevent is generating callbacks more quickly than they are getting resolved (because of the time update takes to resolve). Here is the error:

too many nested evaluations (infinite loop?)
while executing
"if [eof $input] {
Stop
} else {
gets $input line
$log insert end $line\n
$log see end
}"
(procedure "Log" line 3)
invoked from within
"Log"


To answer your other question, let me use an example. I have written a program count which prints the integers [0 - 65535] to stdout; it takes ~20 sec to complete. I want log to display that output in real time. Currently, log won't display the output until after count has terminated. However, if I double-click on the text widget while count is running, the log gets "updated". So, if I were to double-click the text widget after count had been running for 10 seconds, log would show the integers up to ~32K. When count terminated, the rest of the integers would be appended to log.

I hope I have explained the problem clearly. Please let me know if you require any clarification, and thanks for responding.
 
I tried using update idletasks instead of update, and that gives me the behavior I was looking for, although it is a bit slower. Thanks for your help.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top