returning GUI elements in function?

48 views
Skip to first unread message

Travis Hinkelman

unread,
Jul 9, 2019, 2:23:09 AM7/9/19
to Racket Users
Hi All,

I was playing around with creating a progress bar. The basic idea was straightforward.

#lang racket/gui

(define frame (new frame%
                   [label "Progress Bar"]
                   [width 300]))

(define hpane (new horizontal-pane%
                   [parent frame]))

(define gauge (new gauge%
                   [label ""]
                   [parent hpane]
                   [range 100]))

(define msg (new message%
                 [parent hpane]
                 [auto-resize #t]
                 [label "0%"]))

(send frame show #t)

(for ([i (in-range 1 101)])
  (sleep 0.05)
  (send gauge set-value i)
  (send msg set-label (string-append (~a i) "%")))


When I tried to take the next step of wrapping this up into a couple of functions, I was completely lost. I don't know how to initialize a frame with child elements by calling a function because all of the elements of the frame only exist in the function and not at the top-level (probably butchering the jargon here; hopefully it makes sense). I wasn't really sure where to look to learn more about doing such a thing. Here is some pseudocode to try to further illustrate my confusion.

(define (initialize-progress-bar)
  ;; insert code that creates progress bar
  ;; i.e., from defining frame to sending frame in code above)

(define (update-progress-bar new-value)
  (send gauge set-value new-value)
  (send msg set-label (string-append (~a new-value) "%")))

(initialize-progress-bar)
(for ([i (in-range 1 101)])
  (sleep 0.05)
  (update-progress-bar i))

Thanks,

Travis

Laurent

unread,
Jul 9, 2019, 4:05:03 AM7/9/19
to Travis Hinkelman, Racket Users
There are several ways to solve this (including deriving classes), but the simplest for you right now is probably to have `initialize-progress-bar' return the gui widgets (in particular `gauge' and `msg'), assign the values to `the-gauge' and `the-msg' (say) from the return values of `(initialize-progress-bar)` call, and then pass these values to `update-progress-bar' so that `gauge' and `msg' have the correct values there.

Does that make sense?

--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/61a3ea75-d285-45d1-90d4-de569c441c8d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Travis Hinkelman

unread,
Jul 9, 2019, 10:14:00 AM7/9/19
to Racket Users
It's funny how just knowing that there is an easy solution to a problem makes the problem easier to solve. My first thought about returning objects (prior to sending initial email) was that I would return all of the objects unnamed but then I was confused about how to specify the parents of the child objects in the `initialize-progress-bar` function. The code below solves my problem. As always, I welcome people sharing alternative ways to write the same code. 

#lang racket/gui

(define (initialize-progress-bar)
  (define frame (new frame%
                     [label "Progress Bar"]
                     [width 300]))

  (define hpane (new horizontal-pane%
                     [parent frame]))

  (define gauge (new gauge%
                     [label ""]
                     [parent hpane]
                     [range 100]))

  (define msg (new message%
                   [parent hpane]
                   [auto-resize #t]
                   [label "0%"]))

  (send frame show #t)
  (values gauge msg))

(define (update-progress-bar new-value)
  (send the-gauge set-value new-value)
  (send the-msg set-label (string-append (~a new-value) "%")))

(define-values (the-gauge the-msg) (initialize-progress-bar))
(for ([i (in-range 1 101)])
  (sleep 0.05)
  (update-progress-bar i))


On Tuesday, July 9, 2019 at 1:05:03 AM UTC-7, Laurent wrote:
There are several ways to solve this (including deriving classes), but the simplest for you right now is probably to have `initialize-progress-bar' return the gui widgets (in particular `gauge' and `msg'), assign the values to `the-gauge' and `the-msg' (say) from the return values of `(initialize-progress-bar)` call, and then pass these values to `update-progress-bar' so that `gauge' and `msg' have the correct values there.

Does that make sense?

To unsubscribe from this group and stop receiving emails from it, send an email to racket...@googlegroups.com.

Simon Schlee

unread,
Jul 9, 2019, 1:01:30 PM7/9/19
to Racket Users
Classes are really nice and easy for tasks like this, it took me a little bit to get used to the class syntax, but now I love them.
I found that it helps to look at real code that uses classes, because the documentation quickly goes into quite advanced/special use cases.
You can use them to wrap-up/encapsulate a bunch of smaller gui parts and then just expose some methods that handle the updates etc. 

As always, I welcome people sharing alternative ways to write the same code.
Here you go:

#lang racket/gui

(define progress-bar%
  (class horizontal-pane%
    (super-new)

    (define gauge (new gauge%
                       [label #f]
                       [parent this]
                       [range 100]))

    ;; initialize to 100% with no auto resize
    ;; this way the label has the right size
    ;; so that everything can be seen
    ;; and it does not "wobble" around while filling up
    (define msg (new message%
                     [parent this]
                     [label "100%"]))

    (define/public (set-value val)
      (send gauge set-value val)
      (send msg set-label (string-append (~a val) "%")))

    ;; set back to 0%
    (set-value 0)))


(module+ main

  (define frame (new frame%
                     [label "Progress Bar"]
                     [width 300]))
  (define progress (new progress-bar% [parent frame]))


  (send frame show #t)
  (for ([i (in-range 1 101)])
    (sleep 0.05)
    (send progress set-value i)))


Reply all
Reply to author
Forward
0 new messages