Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Racket: using events in a frame% window

I'm learning Racket (formerly PLT Scheme, a LISP dialect) and try to discover how to handle events different than paint-callback (maybe it's not even one).

I hoped a lot from this part of the doc but on-char and on-event seem to do nothing that could interest me (or nothing at all).

Plus, I don't understand eventspaces, queue-callback and their uses. An example would be a cool thing! I'll be thankful to the nice man who'll write me one :).

Here's my code:

(define game (new frame%))

(define gameLay (class canvas% (super-new)))

(new gameLay
     [parent game]
     [paint-callback (λ (canvas dc) #|draw things|#)])

I want to use something like "on-mouse-click-left" (which doesn't exist) the way I use "paint-callback" but I think I need to add steps (I've read about eventspaces etc.). I know it doesn't work but here's the hypothetical code I'm searching for:

(new gameLay
     [parent game]
     [paint-callback (λ (canvas dc) #|draw things|#)]
     [on-mouse-click-left (λ (canvas dc) #|do other things|#)])
like image 446
L01man Avatar asked Sep 03 '11 15:09

L01man


1 Answers

Here's a little program using canvases and keyboard events. Once you've pressed an arrow key, the canvas shows the last one you pressed.

#lang racket/gui

(define game-canvas%
  (class canvas%
    (inherit get-width get-height refresh)

    ;; direction : one of #f, 'left, 'right, 'up, 'down
    (define direction #f)

    (define/override (on-char ke)
      (case (send ke get-key-code)
        [(left right up down)
         (set! direction (send ke get-key-code))
         (refresh)]
        [else (void)]))

    (define/private (my-paint-callback self dc)
      (let ([w (get-width)]
            [h (get-height)])
        (when direction
          (let ([dir-text (format "going ~a" direction)])
            (let-values ([(tw th _ta _td)
                          (send dc get-text-extent dir-text)])
              (send dc draw-text
                    dir-text 
                    (max 0 (/ (- w tw) 2))
                    (max 0 (/ (- h th) 2))))))))

    (super-new (paint-callback (lambda (c dc) (my-paint-callback c dc))))))

(define game-frame (new frame% (label "game") (width 600) (height 400)))
(define game-canvas (new game-canvas% (parent game-frame)))
(send game-frame show #t)

Every frame has an eventspace that manages event dispatching. The on-char method is an event handler; it is run in the eventspace handler thread. No more events will be processed until your on-char method finishes. So if you want to do something complicated, you might want to create a separate thread and do the computation over there. One simple way to do that is to make another eventspace, one that doesn't handle events for any frame, but that handles "events" you send it using queue-callback. For example, replace the definition of on-char above with this:

(define aux-eventspace (make-eventspace))

(define/override (on-char ke)
  (parameterize ((current-eventspace aux-eventspace))
    (queue-callback
     (lambda ()
       (case (send ke get-key-code)
         ((left right up down)
          (set! direction (send ke get-key-code))
          (refresh))
         (else (void)))))))

The function given to queue-callback is run in a separate thread. You can insert some printouts, delays, or whatever to convince yourself that the main eventspace can still process events while the other one handles your callback.

like image 126
Ryan Culpepper Avatar answered Oct 14 '22 19:10

Ryan Culpepper