Canvas 使用tcl/tk画布进行实时打印

Canvas 使用tcl/tk画布进行实时打印,canvas,plot,tcl,tk,Canvas,Plot,Tcl,Tk,我试图使用tcl/tkcanvas实用程序在文件中绘制实时更改。我编写了一个简单的代码来查找文件中的差异,并使用.c create line$oldx$oldy$newx$newy命令对其进行打印 我的代码有一个while循环来不断检查文件中的更改。当我注释掉while循环时,绘图画布会很好地打开,但是当我取消注释while循环时,绘图画布根本不会打开 请建议编辑,代码: #!/usr/bin/wish #PROGRAM 2 : Print something when a file is ch

我试图使用
tcl/tk
canvas实用程序在文件中绘制实时更改。我编写了一个简单的代码来查找文件中的差异,并使用
.c create line$oldx$oldy$newx$newy
命令对其进行打印

我的代码有一个while循环来不断检查文件中的更改。当我注释掉while循环时,绘图画布会很好地打开,但是当我取消注释while循环时,绘图画布根本不会打开

请建议编辑,代码:

#!/usr/bin/wish
#PROGRAM 2 : Print something when a file is changed
#
#package require Tk

#graph prep
 set width 100
 set height 100
 canvas .c -width $width -height $height -background white
 pack .c

#bind .c <Configure> {
#    bind .c <Configure> {}
#    .c xview scroll 0 unit
#    set t 0
#}
#set t 0
#.c create line $t 239 [expr $t + 5] 239 -fill gray
.c create line 0 12 1 13

#Initial reading
 set filename "data.txt"
 #puts $filename
 if [file exists $filename] {
     #puts "file exits!"
    set accessTime [file mtime $filename]
    #puts $accessTime
 }
 #opening file
 set a [open $filename]
 set lines [split [read -nonewline $a] "\n"]
 close $a;                          # Saves a few bytes :-)
 #puts [llength $lines]

 #printing file
 set oldx 0
 set oldy [lindex $lines 0]
 for {set i 1} {$i < [llength $lines]} {incr i} {
     #puts "$i : [lindex $lines $i]"
     set newx $i
     set newy [lindex $lines $i]
     .c create line $oldx $oldy $newx $newy
     set oldx $newx
     set oldy $newy
 }

## after 10000
## #looping to detect change
 while 1 {
     if [file exists $filename] {
    after 1000      
         #  check if new access time
        set nAccessTime [file mtime $filename]
        if {$accessTime != $nAccessTime} {
        #puts $nAccessTime
            #puts "found new"
        #update access time
            set accessTime $nAccessTime
        #read new lines 
        set a [open $filename]
        set lines [split [read -nonewline $a] "\n"]
        close $a;                          # Saves a few bytes :-)
        #puts [llength $lines]

        for {} {$i < [llength $lines]} {incr i} {
            #puts "$i : [lindex $lines $i]"
            set newx $i
            set newy [lindex $lines $i]
            .c create line $oldx $oldy $newx $newy
            set oldx $newx
            set oldy $newy
        }
        }
     }
 }
#/usr/bin/wish
#程序2:文件更改时打印内容
#
#包装需要Tk
#图表准备
设置宽度100
设置高度100
canvas.c-宽度$width-高度$height-背景白色
包装c
#bind.c{
#bind.c{}
#.c xview滚动0单元
#设置t0
#}
#设置t0
#.c创建行$t 239[expr$t+5]239-填充灰色
.c创建行0 12 1 13
#初读
设置文件名“data.txt”
#放入$filename
如果[文件存在$filename]{
#放入“文件退出!”
设置accessTime[文件mtime$filename]
#将$accessTime放入
}
#打开文件
设置[打开$filename]
设置行[拆分[读取-非WLINE$a]“\n”]
收盘价$a;#保存几个字节:-)
#放置[L长度$行]
#打印文件
将oldx设置为0
设置旧的[lindex$行0]
对于{set i 1}{$i<[llength$行]}{incr i}{
#放置“$i:[lindex$line$i]”
设置newx$i
设置新的[lindex$行$i]
.c创建行$oldx$oldy$newx$newy
设置oldx$newx
设置旧的$newy
}
##一万以后
###循环检测变化
而1{
如果[文件存在$filename]{
1000后
#检查是否有新的访问时间
设置nAccessTime[文件mtime$filename]
如果{$accessTime!=$nAccessTime}{
#把$nAccessTime
#放入“新发现”
#更新访问时间
设置accessTime$nacessTime
#读新台词
设置[打开$filename]
设置行[拆分[读取-非WLINE$a]“\n”]
关闭$a;#保存几个字节:-)
#放置[L长度$行]
对于{}{$i<[llength$line]}{incr i}{
#放置“$i:[lindex$line$i]”
设置newx$i
设置新的[lindex$行$i]
.c创建行$oldx$oldy$newx$newy
设置oldx$newx
设置旧的$newy
}
}
}
}

这是在Tk中执行动态时间驱动更新的典型问题(动画也有同样的问题)。问题是Tk仅在事件循环空闲时重新绘制自身;它推迟了实际的绘图活动,直到这种情况发生,允许它将多个状态更改分组为一个重画(极大地提高了实际效率)。大多数情况下,这是透明的,但当你有一个驱动循环,如你写的,你没有得到任何更新发生

解决此问题的快速方法是更改:

after 1000
致:

它在暂停期间运行事件循环,而不是完全停止进程。另一种方法是将其改为:

update
after 1000
但这显然是不好的,因为这意味着应用程序在等待过程中没有响应

更好的方法是重写代码,以便处理计时器回调中的更改。这对您的代码来说是一个相当大的外科手术……除非您有Tcl 8.6,当您可以使用协同程序轻松完成时:

 package require Tcl 8.6;    # <<<< GOOD STYLE
 package require Tk;         # <<<< GOOD STYLE

 set width 100
 set height 100
 canvas .c -width $width -height $height -background white
 pack .c

.c create line 0 12 1 13

#Initial reading
 set filename "data.txt"
 #puts $filename
 if [file exists $filename] {
     #puts "file exits!"
    set accessTime [file mtime $filename]
    #puts $accessTime
 }
 #opening file
 set a [open $filename]
 set lines [split [read -nonewline $a] "\n"]
 close $a;                          # Saves a few bytes :-)
 #puts [llength $lines]

 #printing file
 set oldx 0
 set oldy [lindex $lines 0]
 for {set i 1} {$i < [llength $lines]} {incr i} {
     #puts "$i : [lindex $lines $i]"
     set newx $i
     set newy [lindex $lines $i]
     .c create line $oldx $oldy $newx $newy
     set oldx $newx
     set oldy $newy
 }

## #looping to detect change
coroutine mainloop apply {{} {         # <<< CHANGED LINE
    global i filename accessTime oldx oldy
    while 1 {
        after 1000 [info coroutine];   # <<< CHANGED LINE
        yield;                         # <<< CHANGED LINE

        if {[file exists $filename]} {
            #  check if new access time
            set nAccessTime [file mtime $filename]
            if {$accessTime != $nAccessTime} {
                #puts $nAccessTime
                #puts "found new"
                #update access time
                set accessTime $nAccessTime
                #read new lines 
                set a [open $filename]
                set lines [split [read -nonewline $a] "\n"]
                close $a;                          # Saves a few bytes :-)
                #puts [llength $lines]

                for {} {$i < [llength $lines]} {incr i} {
                    #puts "$i : [lindex $lines $i]"
                    set newx $i
                    set newy [lindex $lines $i]
                    .c create line $oldx $oldy $newx $newy
                    set oldx $newx
                    set oldy $newy
                }
            }
         }
     }
}}

包需要Tcl 8.6;#我可能错了,但我相信这与事件处理程序有关,或者我认为它的名字是。基本上,tk元素只有在没有挂起的任务要做并且在您的情况下,总是有事情要做(包括在循环之间等待)之后才会绘制。我宁愿将整个部分放在
proc
中的while循环中,并调用该过程一次,在过程结束时,在1000 procname
之后使用
来创建循环。@Jerry更容易使用Tcl 8.6协程。简单多了,谢谢多纳尔。该图表现在即将出现,但它不会使用文件中的新值进行更新。有什么建议吗?我想出来了。我没有被添加到全局变量列表中
global i filename accessTime oldx oldy
起作用了。@guptasonal我已将其编辑到我的答案中;我只是错过了这里用的那种方式…
 package require Tcl 8.6;    # <<<< GOOD STYLE
 package require Tk;         # <<<< GOOD STYLE

 set width 100
 set height 100
 canvas .c -width $width -height $height -background white
 pack .c

.c create line 0 12 1 13

#Initial reading
 set filename "data.txt"
 #puts $filename
 if [file exists $filename] {
     #puts "file exits!"
    set accessTime [file mtime $filename]
    #puts $accessTime
 }
 #opening file
 set a [open $filename]
 set lines [split [read -nonewline $a] "\n"]
 close $a;                          # Saves a few bytes :-)
 #puts [llength $lines]

 #printing file
 set oldx 0
 set oldy [lindex $lines 0]
 for {set i 1} {$i < [llength $lines]} {incr i} {
     #puts "$i : [lindex $lines $i]"
     set newx $i
     set newy [lindex $lines $i]
     .c create line $oldx $oldy $newx $newy
     set oldx $newx
     set oldy $newy
 }

## #looping to detect change
coroutine mainloop apply {{} {         # <<< CHANGED LINE
    global i filename accessTime oldx oldy
    while 1 {
        after 1000 [info coroutine];   # <<< CHANGED LINE
        yield;                         # <<< CHANGED LINE

        if {[file exists $filename]} {
            #  check if new access time
            set nAccessTime [file mtime $filename]
            if {$accessTime != $nAccessTime} {
                #puts $nAccessTime
                #puts "found new"
                #update access time
                set accessTime $nAccessTime
                #read new lines 
                set a [open $filename]
                set lines [split [read -nonewline $a] "\n"]
                close $a;                          # Saves a few bytes :-)
                #puts [llength $lines]

                for {} {$i < [llength $lines]} {incr i} {
                    #puts "$i : [lindex $lines $i]"
                    set newx $i
                    set newy [lindex $lines $i]
                    .c create line $oldx $oldy $newx $newy
                    set oldx $newx
                    set oldy $newy
                }
            }
         }
     }
}}