Обновление ракетки - сейчас, нарезка и выход - PullRequest
2 голосов
/ 23 июня 2011

Я написал несколько простых racket программ с графическим интерфейсом для подготовки к уроку, который я преподаю осенью. У меня проблемы с анимацией. Я использую базовый холст и использую модель для анимации, в которой весь холст обновляется в каждом кадре, вызывая процедуру рисования. Пример программы приведен ниже.

Моя проблема в том, что я должен либо запустить анимацию как отдельный thread, либо вызывать yield после каждого экземпляра refresh-now. Почему это? Я ожидал, что refresh-now заставит изображение обновиться сразу, без дополнительной работы с моей стороны.

Я прочитал примеры анимации на страницах racket и вижу, что они обычно рисуют прямо на холсте. Я понимаю, что, поскольку холст имеет двойную буферизацию, это работает нормально ... но для моего приложения проще просто перенести нагрузку на процедуру рисования, так как в любом случае мне нужна рабочая процедура рисования в случае минимизации и т. Д. (Конечно , yield не является огромным бременем, но было бы легче учить, если бы не было необходимости.)

Спасибо
John

#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)
)))

1 Ответ

4 голосов
/ 24 июня 2011

Это не ответ на ваш вопрос о 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; Я вставил его, чтобы имитировать поведение вашего исходного кода.

Таймер создается в том же пространстве событий, что и фрейм, а пространство событий имеет поток обработки событий, поэтому вам не нужно явно создавать свой собственный поток.

Как разрабатывать программы, 2-е изд. имеет другой подход к анимации, где холст и обновления управляются автоматически. Вы просто вызываете big-bang с функциями, которые (функционально) обновляют «состояние мира» и отображают «состояние мира» в виде изображения. В зависимости от того, чему именно вы учите, это может вам пригодиться, а может и не пригодиться.

...