我有以下倒数计时器的代码。它开始没事,但按下停止按钮时不会停止。
#lang racket/gui
(define myframe (new frame% [label "Timer"] [x 500] [y 200] ) )
(define tfsecs (new text-field% [parent myframe] [label "Secs:"]))
(define msgbmi (new message%
[parent myframe] [auto-resize #t] [label ""] ))
(define stopflag #f)
(define (OnButtonPressFn n)
(sleep 1)
(set! n (sub1 n))
(define m 0)
(send msgbmi set-label "")
(for((i (in-naturals)) #:break stopflag)
(set! m (- n i))
; (printf "running; i= ~a~n" m)
(send msgbmi set-label (number->string m))
(sleep 1) ) )
(define startbutton
(new button% [parent myframe] [label "Start"]
(callback (lambda (b e)
(define secs (string->number (send tfsecs get-value)))
(when secs (OnButtonPressFn secs))))))
(define stopbutton
(new button% [parent myframe] [label "Stop"]
(callback (lambda (b e)
(set! stopflag #t)))))
(send myframe show #t)
如果我将for循环限制为0,它会停止。但是我想让它继续显示停止按钮被按下的时间。
显然,运行循环不会读取停止按钮设置的停止标志。如何纠正?如何在此处使停止按钮正常工作?
答案 0 :(得分:1)
让我们按照预期的控制流程进行操作。
首先我们点击开始按钮。系统生成一个事件。事件处理程序(调用回调)并处理单击。然后点击停止按钮。系统生成一个新事件,并调用停止按钮的事件处理程序。
程序中的问题是启动按钮的事件处理程序永远不会返回。系统一次只处理一个事件,因此如果您从未从事件处理程序返回,则不会处理任何后续事件。
解决问题的一种方法是启动一个新线程来完成实际工作:
(define (OnButtonPressFn n)
(thread (λ ()
(sleep 1)
(set! n (sub1 n))
(define m 0)
(send msgbmi set-label "")
(for((i (in-naturals)) #:break stopflag)
(set! m (- n i))
; (printf "running; i= ~a~n" m)
(send msgbmi set-label (number->string m))
(sleep 1) ) )))
此事件处理程序创建一个新线程(与事件循环并发运行),然后立即返回。事件循环能够处理新事件。同时新线程完成工作(这里打印数字)。