0
votes

I'm trying to draw on a canvas that is in the top level of my Tcl/Tk script, but from inside a call by fileevent like this:

canvas .myCanvas {}

proc plot_Data { myC inp } { $myC create rectangle {} }

fileevent $inp readable [list plot_Data .myCanvas $inp ]

pack .myCanvas

I have found out that the script called by fileevent (plot_Data) lives in a different space.

The script for a file event is executed at global level (outside the context of any Tcl procedure) in the interpreter in which the fileevent command was invoked.

I cannot make the two meet. I have definitely narrowed it down to this: plot_Data just can't access .myCanvas . Question: How can the fileevent script plot on the canvas?

The goal of this is live plotting, by the way. $inp is a pipe to a C-program that reads data from a measurement device. It is imho rightly configured with fconfigure $inp -blocking 0 -buffering none.

1
proc plot_Data{ myC inp } ... -- is that your real code or a typo? You need a space between the proc name and the argument list.glenn jackman
also the scripts registered with fileevent are evaluated as-is, not with any additional arguments added. So plot_Data .myCanvas will give an error about missing arguments.evil otto
Sorry, I should have said it's pseudo-code, glennjackman. Just to show how I'm trying to do it. And @evilotto, there's this example in the tcl man pages: fileevent $chan readable [list GetData $chan] . I changed my post to reflect how I'm doing it, and the script CAN take the arguments - because it can access the $inp file descriptor I'm passing to it, and it DOES receive $myC as .myCanvas. However, it can't draw on it.curious_weather
What makes you believe that plot_Data can't draw on the canvas? If you are you getting an error, please include the error message. If you are simply seeing "nothing" happen, the problem could be elsewhere, and including your real code (rather than pseudocode) will help find the problem.evil otto

1 Answers

0
votes

Callback scripts (except for traces, which you aren't using) are always called from the context of the global namespace. They cannot see any stack frames above them. This is because they are called at times that aren't closely controlled; there's no telling what the actual stack would be, so it is forced into a known state.

However, canvases (and other widgets) have names in the global namespace as well. Your callbacks most certainly can access them, provided the widget has not been destroyed, and might indeed be working. You just happen to have given it an empty list of coordinates to create, which is not usually legal to use with a canvas item.


Since you are using non-blocking I/O, you need to be aware that gets may return the empty string when reading an incomplete line. Use fblocked to determine if a partial read happened; if it does, the data is in a buffer on the Tcl side waiting for the rest of the line to turn up, and it is usually best to just go to sleep and wait for the next fileevent to fire.

A problem that might bite you overall is if the C program is in fully buffered mode; this is true by default when writing output from C to a pipe. Setting the buffering on the Tcl side won't affect it; you need to use setvbuf on the C side, or insert regular fflush calls, or use Expect (which pretends to be an interactive destination, though at quite a lot of cost of complexity of interaction) or even unbuffer (if you can find a copy).