-2

Let say, there is a.tcl that contains infinite loop condition, e.g.,

while {1} {
    puts $val 
}

I want to implement a tk-button, that executes a.tcl file and continues to run and print $val in tk-text window at regular interval of time say every 1sec. Also, when we click on that button again, it should stop running a.tcl

Note : I tried using exec tclsh a.tcl but it hangs the tk-window because of infinite while loop in a.tcl

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • I've not got time to answer properly right now, but you need to launch the subprocess as a pipeline and then kill the subprocess and close the pipe when you want things to stop. **_What platform are you on?_** That is (unfortunately) significant for this question. Also, what do you want to happen to the output of `a.tcl`? – Donal Fellows Feb 17 '21 at 09:45
  • You could probably use a thread instead of a whole separate process... – Shawn Feb 17 '21 at 17:20

1 Answers1

1

If, instead of using exec, you launch the subprocess with:

set pipeline [open |[list tclsh a.tcl]]

then the GUI will remain active. However, you'll probably want to read from the pipeline from time to time.

proc line_per_second {pipeline} {
    puts [gets $pipeline]
    after 1000 line_per_second $pipeline
}
line_per_second $pipeline

When you close $pipeline, it should shut things down (because the OS pipe gets closed).

Note that for real code, as opposed to code which is just spewing the same line over and over as fast as possible, you can use a readable fileevent to trigger your call to gets instead.

proc read_line {pipeline} {
    gets $pipeline line
    if {[eof $pipeline]} {
        close $pipeline
    } else {
        puts $line
    }
}
fileevent $pipeline readable [list read_line $pipeline]

However, with your specific script that might trigger too often and starve the GUI of events a bit. It's only really a problem with very large amounts of output.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215