multithreading - Racket refresh-now, thread, and yield

标签 multithreading user-interface racket

我一直在编写一些简单的 racket GUI 程序来为我在秋季教授的类(class)做准备。我在动画方面遇到了一些问题。我正在使用一个基本的 Canvas ,并使用动画模型,其中通过调用绘制过程,整个 Canvas 在每一帧都被刷新。下面是一个示例程序。

我的问题是我必须将动画作为单独的线程运行,或者在每个refresh-now实例之后调用yield .为什么是这样?我希望 refresh-now 能够立即刷新图像,而无需我进行额外的工作。

我已经阅读了racket 页面上的动画示例,发现它们通常直接绘制到 Canvas 上。我知道由于 Canvas 是双缓冲的,所以效果很好......但是对于我的应用程序来说,让绘画程序承担负载更容易,因为无论如何我都需要一个工作绘画程序以防最小化等。(当然, 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)
)))

最佳答案

这不是关于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)])))))

如果你根据三角形的状态重新定义你的停止条件,你可以去掉辅助的timer-counter;我将其放入以模仿您原始代码的行为。

计时器是在与框架相同的事件空间中创建的,事件空间有一个事件处理线程,这就是为什么您不必显式创建自己的线程的原因。

How to Design Programs, 2nd ed有另一种动画方法,自动管理 Canvas 和更新。您只需使用函数调用 big-bang 即可(在功能上)更新“世界状态”并将“世界状态”渲染为图像。它可能对您有用,也可能没有用,具体取决于您所教授的内容。

关于multithreading - Racket refresh-now, thread, and yield,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6459693/

相关文章:

java - 如果使用 java.util.concurrent 数据结构,是否需要使用 "synchronized"关键字来获取/添加?

JavaFX布局: all in Grid vs Separator for each cell

android - 导航栏和状态栏不隐藏

scheme - Racket 开关语句宏

python - 在进程之间共享 bool 值

c - 我什么时候应该在任务中使用线程? - FreeRTOS

scheme - 如何在 Breakout 中让球与砖 block 碰撞( Racket )

lisp - SICP - 通过加法乘法

multithreading - 如何终止一个线程?

java - 如何退出或退出从 Java 中的主 JWindow 创建的从属 JWindow?