8

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|#)])
Svante
  • 50,694
  • 11
  • 78
  • 122
L01man
  • 1,521
  • 10
  • 27
  • 1
    I think that an example of what you want to do would really help with showing how it is done. – Svante Sep 03 '11 at 16:47
  • Here is 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.). – L01man Sep 03 '11 at 18:46
  • I have put that information into your question. Please correct the code; there are mismatched parentheses and braces at the end, so it might not be what you intended. To make the example clearer, just put your hypothetical `on-mouse-click` into the example just the way you would like to use it. – Svante Sep 03 '11 at 19:06
  • Sorry now it's done. I first shortened the code in order to give only what is concerned; then I couldn't edit because of the 5 minutes delay message that didn't disappear even after 1 hour. So in the first post I added the hypothetical code and corrected the current one. But don't worry, I'll look at the answer given by Ryan Culpepper which seems clear. – L01man Sep 04 '11 at 10:27

1 Answers1

11

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.

Sam Tobin-Hochstadt
  • 4,983
  • 1
  • 21
  • 43
Ryan Culpepper
  • 10,495
  • 4
  • 31
  • 30
  • Ooooh I see thanks a lot. When I [link](http://docs.racket-lang.org/search/index.html?q=key&q=get-key-code&q=refresh)searched "key" in the search bar[/link] I didn't find anything. Thanks to your code I'll be able to finish my little project (happy)! – L01man Sep 04 '11 at 11:20
  • If an answer works for you, you should click "accept" to indicate to others that it worked. – Sam Tobin-Hochstadt Sep 04 '11 at 16:15
  • You're right, I've just found this button (the tick floatting on the left of the answers). Thank you Ryan, it works perfecly. Really, really, great! – L01man Sep 04 '11 at 17:08