# Racket/gui canvas Hello World

**URL:** <https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522>\
**Category:** Questions & Answers\
**Tags:** gui\
**Created:** [November 21, 2023, 11:25am UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522 "2023-11-21T11:25:41Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 21, 2023, 11:25am UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/1 "2023-11-21T11:25:41Z")

</div>

Can anybody give me a simple hello-world example using the racket/gui canvas? Just a very minimal program opening a window with a canvas and drawing a text in the middle. I am a newbie and could not find something similar.

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [November 21, 2023, 2:03pm UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/2 "2023-11-21T14:03:40Z")

</div>

You may want to look at this repo, starting with task 1:

[

 ![7GUI.png](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/7/73e0139b372a01f41ad9e686a47dfff31ea0e965.png)

[mfelleisen/7GUI: the 7 gui project](https://github.com/mfelleisen/7GUI)  
[github.com](https://github.com/mfelleisen/7GUI)

]([GitHub - mfelleisen/7GUI: the 7 gui project](https://github.com/mfelleisen/7GUI))

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 21, 2023, 2:25pm UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/3 "2023-11-21T14:25:49Z")

</div>

Here's another example.

```scheme
#lang racket
(require pict racket/gui/base)

; an example pict to draw
(define p
  (scale
   (for/fold ([p (filled-rectangle 400 400)])
             ([i (in-range 7)])
     (vc-append
      (scale p (/ 1 3))
      (hc-append
       (scale p (/ 1 3))
       (scale p (/ 1 3)))))
   10))

;; code that draws the pict into a canvas
;; (this is a simplified version of `show-pict`)
(define (draw c dc)
  (define-values (cw ch) (send c get-client-size))
  (define w (pict-width p))
  (define h (pict-width p))
  (draw-pict p dc (- (/ cw 2) (/ w 2)) (- (/ ch 2) (/ h 2))))
(define f (new frame% [label ""] [width 400] [height 400]))
(define c (new canvas% [parent f] [paint-callback draw]))
(send f show #t)

```

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 21, 2023, 2:49pm UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/4 "2023-11-21T14:49:28Z")

</div>

> [@robby](#):
>
> example

I noticed that draw is called always twice on my system: for example at the start and during each window resize. Is this normal or a bug of my window manager?

```scheme
#lang racket
(require pict racket/gui/base)

; an example pict to draw
(define p
  (scale
   (for/fold ([p (filled-rectangle 400 400)])
             ([i (in-range 7)])
     (vc-append
      (scale p (/ 1 3))
      (hc-append
       (scale p (/ 1 3))
       (scale p (/ 1 3)))))
   10))

(define counter
  (let ((x 0))
    (lambda ()
      (set! x (+ x 1))
      (printf "counter: ~s\n" x))))

;; code that draws the pict into a canvas
;; (this is a simplified version of `show-pict`)
(define (draw c dc)
  (counter)
  (define-values (cw ch) (send c get-client-size))
  (define w (pict-width p))
  (define h (pict-width p))
  (draw-pict p dc (- (/ cw 2) (/ w 2)) (- (/ ch 2) (/ h 2))))
(define f (new frame% [label ""] [width 400] [height 400]))
(define c (new canvas% [parent f] [paint-callback draw]))
(send f show #t)

```

---

<div class="post-metadata">

**Author:** ![ceving](https://avatars.discourse-cdn.com/v4/letter/c/a3d4f5/32.png) [@ceving](https://racket.discourse.group/u/ceving)\
**Post date:** [November 21, 2023, 3:06pm UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/5 "2023-11-21T15:06:04Z")

</div>

I think I got it:

```scheme
#lang racket/gui

(define frame (new frame%
                   [label "Hello, World!"]
                   [width 300]
                   [height 200]))

(define panel (new panel%
                   [parent frame]
                   [alignment '(center center)]))

(define (draw-text dc text)
  (let*-values ([(text-width text-height d a)
                 (send dc get-text-extent text)]
                [(dc-width dc-height)
                 (send dc get-size)])
    (send dc draw-text text
          (/ (- dc-width text-width) 2)
          (/ (- dc-height text-height) 2))))
  
(define (do-paint canvas dc)
  (draw-text dc "Hello, World!"))

(define canvas (new canvas%
                    [parent panel]
                    [paint-callback do-paint]))

(send frame show #t)

```

Another example without panel but with a custom class and event logging.

```scheme
#lang racket/gui

(define hello-canvas%
  (class canvas%
    (init parent)
    (super-new (parent parent))

    (let ((dc (send this get-dc)))
      (send dc set-font (make-font #:size 24 #:face "Fira Code")))

    (define/override (on-event event)
      (printf "event: x=~s y=~s mouse=~s\n"
              (send event get-x)
              (send event get-y)
              (send event get-event-type)))

    (define/override (on-char event)
      (printf "event: key=~s\n"
              (send event get-key-code)))

    (define/public (draw-text-center text)
      (let ((dc (send this get-dc)))
        (let*-values ([(text-width text-height d a)
                       (send dc get-text-extent text)]
                      [(dc-width dc-height)
                       (send dc get-size)])
          (send dc draw-text text
                (/ (- dc-width text-width) 2)
                (/ (- dc-height text-height) 2)))))

    (define/override (on-paint)
      (let ((label (let loop ((area this))
                     (let ((p (send area get-parent)))
                       (if p
                           (loop p)
                           (send area get-label))))))
      (send this draw-text-center label)))
    ))

(define frame (new frame%
                   [label "Hello, World!"]
                   [width 600]
                   [height 400]))

(define canvas (new hello-canvas%
                    [parent frame]))

(send frame show #t)

```

Same with bounding box and baseline:

```scheme
#lang racket/gui

(define shell%
  (class canvas%
    (init parent)
    (super-new (parent parent))

    (let ((dc (send this get-dc)))
      (send dc set-font (make-font #:size 24 #:face "Fira Code"))
      (send dc set-pen "black" 0 'solid)
      (send dc set-smoothing 'unsmoothed)
      (send dc set-brush "white" 'transparent))

    (define/override (on-event event)
      (printf "event: x=~s y=~s mouse=~s\n"
              (send event get-x)
              (send event get-y)
              (send event get-event-type)))

    (define/override (on-char event)
      (printf "event: key=~s\n"
              (send event get-key-code)))

    (define/public (draw-text-center text bounding-box baseline)
      (let ((dc (send this get-dc)))
        (let*-values ([(dc-width dc-height) (send dc get-size)]
                      [(text-width text-height baseline-height extra-height)
                       (send dc get-text-extent text)])
          (let* ((offset-x (/ (- dc-width text-width) 2))
                 (offset-y (/ (- dc-height text-height) 2))
                 (baseline-y (- (+ offset-y text-height) baseline-height))
                 (margin-x (- (+ offset-x text-width) 1)))
            (send dc draw-text text offset-x offset-y)
            (when bounding-box
              (send dc draw-rectangle offset-x offset-y text-width text-height))
            (when baseline
              (send dc draw-line offset-x baseline-y margin-x baseline-y))))))

    (define/override (on-paint)
      (let ((label (let loop ((area this))
                     (let ((p (send area get-parent)))
                       (if p
                           (loop p)
                           (send area get-label))))))
      (send this draw-text-center label #t #t)))
    ))

(define frame (new frame%
                   [label "Hello, World!"]
                   [width 600]
                   [height 400]))

(define canvas (new shell%
                    [parent frame]))

(send frame show #t)

```

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [November 21, 2023, 3:59pm UTC](https://racket.discourse.group/t/racket-gui-canvas-hello-world/2522/6 "2023-11-21T15:59:14Z")

</div>

> [@ceving](#):
>
> I noticed that draw is called always twice on my system: for example at the start and during each window resize. Is this normal or a bug of my window manager?

It may just be the vagaries of the different platforms. I don't see it on mac os, and I think that racket avoids offering any guarantees about how many times or at exactly which moments the draw callbacks are called.
