Joh*_*edl 3 user-interface multithreading racket
我一直在编写一些简单的racketGUI 程序,为我秋季教授的课程做准备。我在动画方面遇到一些问题。我使用基本画布,并使用动画模型,其中通过调用绘制过程,每帧刷新整个画布。下面是一个示例程序。
我的问题是我必须要么将动画作为单独的运行thread,要么yield在每个实例之后调用refresh-now。为什么是这样?我希望refresh-now图像能够立即刷新,而无需我进行额外的工作。
我已经阅读了页面上的动画示例racket,发现它们通常直接绘制到画布上。我知道,由于画布是双缓冲的,所以效果很好......但对于我的应用程序来说,让绘画程序承担负载会更容易,因为无论如何我都需要一个工作绘画程序,以防最小化等。(当然,这yield并不是一个很大的负担,但如果不需要的话,教学会更容易。)
谢谢,
约翰
#lang racket
; Demonstrate simple animation in Racket
(require racket/gui)
(define min-x 0)
(define min-y 0)
(define max-x 200)
(define max-y 200)
; Three vertexes of the triangle, expressed relative to a starting x and y location.
(define triangle-vertexes [list
(list 10 0)
(list 0 20)
(list 20 20)])
(define triangle-x 20)
(define triangle-y 20)
; Move a triangle by a (delta-x, delta-y) pair
(define (move-triangle adjust)
(set! triangle-x (+ triangle-x (first adjust)))
(set! triangle-y (+ triangle-y (second adjust))))
; Adjust the location of a vertex by adding an (x,y) adjustment to it.
; Could also be defined using map.
(define (triangle-adjust adjust vertex)
(list (+ (first adjust) (first vertex))
(+ (second adjust) (second vertex))))
; Create the paint-callback function.
; It should:
; - draw a triangle at the current location
(define (draw-triangle dc)
(let ((vertex1 (triangle-adjust (list triangle-x triangle-y) (first triangle-vertexes)))
(vertex2 (triangle-adjust (list triangle-x triangle-y) (second triangle-vertexes)))
(vertex3 (triangle-adjust (list triangle-x triangle-y) (third triangle-vertexes))))
(send dc draw-line (first vertex1) (second vertex1) (first vertex2) (second vertex2))
(send dc draw-line (first vertex2) (second vertex2) (first vertex3) (second vertex3))
(send dc draw-line (first vertex3) (second vertex3) (first vertex1) (second vertex1))))
(define frame (new frame%
[label "Animation Example"]
[width 800]
[height 800]))
(define triangle-canvas (new canvas% [parent frame]
[paint-callback
(lambda (canvas dc)
(display "callback called")
(draw-triangle dc))]))
(send frame show #t)
; run a thunk (a procedure of zero arguments) n times
; only useful if thunk has side-effects
(define (loop n thunk)
(cond
((> n 0) (thunk)
(loop (- n 1) thunk))
(else false)))
; Animate the triangle. We have to either run this in a different thread from
; the event loop or yield each time we want something to be drawn.
(define (animate-triangle)
(loop 30
(lambda ()
(move-triangle (list 10 10))
(send triangle-canvas refresh-now)
; (send triangle-canvas flush)
(yield)
; (sleep 0.1)
)))
Run Code Online (Sandbox Code Playgroud)
这不是您关于 的问题的答案refresh-now,但显式线程和循环的更好替代方案是该类timer%:
;; This goes after (send frame show #t), replacing loop and animate-triangle
(define timer-counter 0)
(define timer
(new timer%
(interval 100) ;; update every 100 ms
(notify-callback
(lambda ()
(cond [(< timer-counter 30)
(set! timer-counter (add1 timer-counter))
(move-triangle (list 10 10))
(send triangle-canvas refresh)]
[else
(send timer stop)])))))
Run Code Online (Sandbox Code Playgroud)
如果您根据三角形的状态重新定义停止条件,您可以摆脱辅助timer-counter; 我将其放入以模仿原始代码的行为。
计时器是在与帧相同的事件空间中创建的,并且事件空间有一个事件处理线程,这就是为什么您不必显式创建自己的线程。
如何设计程序,第二版有另一种动画方法,其中画布和更新是自动管理的。您只需调用big-bang函数即可(从功能上)更新“世界状态”并将“世界状态”渲染为图像。具体取决于您所教的内容,它可能对您有用,也可能没有用。