s c h e m a t i c s : c o o k b o o k

/ Cookbook.GUIWidgetAggregation

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Aggregating Widgets in a Single Widget

Problem

You would like to deal with many widgets as though they were a single widget.

Solution

#lang scheme/gui
  
  (define my-widget%
    (class vertical-panel%

       (init-field parent)

       (super-new [parent parent])
      
         (new button%
           [label "Press Me"]
           [parent this] [callback void])
         (new text-field% 
           [label "Enter Text"]
           [parent this] [callback void])))
  
  (define top-frame (instantiate frame% () (label "Example")))
  (define new-my-widget (new my-widget% (parent top-frame)))
  (send top-frame show #t)

Addenda

this can be done as a macro;

#lang scheme/gui

;; create aggregate widget
(define-syntax define-aggregate-widget
  (syntax-rules ()
  ((_ new-aggregate-widget-classname container . sub-widget-args)
  (define new-aggregate-widget-classname
    (class container
      (init-field parent) 
      (super-new (parent parent))
      . 
      sub-widget-args   ;; child widget macros in order
      )))))

;; embed (parent this) into the arguments of the 'new' form
(define-syntax new-widget
 (syntax-rules ()
  ((_ new-widget-classname . args)
   (new new-widget-classname (parent this) . args))))

(define-aggregate-widget my3% horizontal-panel%
            (new-widget button% (label "Press Me") (callback void) (stretchable-width #t))
            (new-widget button% (label "Press Me1") (callback void) (stretchable-width #t))
            (new-widget button% (label "Press Me2") (callback void) (stretchable-width #t))
            (new-widget button% (label "Press Me3") (callback void) (stretchable-width #t))
            (new-widget button% (label "Press Me4") (callback void) (stretchable-width #t))
         (new-widget text-field% (label "Enter Text") (callback void) (stretchable-width #t)))
  
(define top-frame (instantiate frame% () (label "Example")))
(define new-my3 (new my3% (parent top-frame)))
(send top-frame show #t)

-- StephenDeGabrielle - 17 Jul 2008

Discussion

GUI programming is non-standard. A PLT Solution has been given.

When designing a GUI, it is common to design widget groups that are reused. This is done by creating a subclass of the panel type and defining the widgets in that class.

The above sample displays a push button with the label "Push Me" above a Text Box with the label "Enter Text".

The first thing to do is start scheme with the graphics toolkit enabled:

#lang scheme/gui
(this is equivalent to importing the required libraries)

Then, we would like to define a new widget class and bind it to a name. It is customary to name classes with a % suffix. This will be a subclass of the vertical-panel% widget which will provide layout geometry for child widgets.

  (define my-widget%
    (class vertical-panel%
   ;...
  ))

Since panel widgets cannot be top level windows (frames in the MrEd and wxWidget nomenclature), we must give this widget a parent that must be set on instantiation. This is done with the init-field expression:

  (init-field parent)

If we wanted, we could set it to an initial value much the same way we set initial values in a let expression.

Next instantiate the vertical-panel[Initialize the superclass]. As we mentioned before, panels cannot be top level windows, so they must have parents. That means we need to pass the parent parameter to the super-instantiate expression:

       (super-new [parent parent])
      

Don't worry that the parent expression has the same name as the parameter. The values are resolved by position in the expression as well as name, so Scheme won't be confused.

The next step is to instantiate the component widgets. This is quite straight forward:

  
         (new button%
           [label "Press Me"]
           [parent this] [callback void])
         (new text-field% 
           [label "Enter Text"]
           [parent this] [callback void])

The keyword ''this'' allows us to place the component widgets (button and text-field) within the vertical-panel.

Constructing and showing the window are straight forward:

  (define top-frame (instantiate frame% () (label "Example")))
  (define new-my-widget (new my-widget% (parent top-frame)))
  (send top-frame show #t)


Comments about this recipe

Refactored to include changes suggested by comments and updated for PLT-Scheme 4+. (please see the history)

Thanks to DanielSilva and EwanHiggs

-- StephenDeGabrielle - 16 Jul 2008

Here is another example - but but the widget is created from drawing toolkit elements, rather than existing widgets.

;  make new widget'scatter-chart%'
;; do this all in Pretty Big language (DrScheme only)
(define scatter-chart% (class pane% ()
                         (init-field parent)
                         ; Make the drawing area
                         (super-instantiate () (parent parent) ; instantiate this FIRST
                           [min-width 100] [stretchable-width #f]
                           (min-height 200) [stretchable-height #f])
                         
                         ;; internal data
                         (define list-of-points '()) ;; start with empty list
                         (define canvas (new canvas% [parent this]  
                                             (paint-callback (lambda (canvas dc) (draw-chart)))
                                             [min-width 100] [stretchable-width #f]
                                             [min-height 200] [stretchable-height #f]
                                             ))
                         (define dc (send canvas get-dc)) ; Get the canvas's drawing context
                         ; Make some pens and brushes for use later
                         (define no-pen (make-object pen% "BLACK" 1 'transparent))
                         (define blue-brush (make-object brush% "BLUE" 'solid))
                         (define yellow-brush (make-object brush% "YELLOW" 'solid))
                         
                         ;; public methods
                         ;; add-point : new-point
                         (define/public (add-point new-point)
                           (set! list-of-points (cons new-point list-of-points)) ;; add to the list
                           (send dc draw-rectangle 0 new-point 200 1)) ;; and draw the line
                         ;; draw-chart : draw a chart based on the list of integers supplied
                         ;; see http://download.plt-scheme.org/doc/371/html/mred/mred-Z-H-397.html
                         (define/public (draw-chart)
                           (send dc set-pen no-pen)
                           (send dc set-brush blue-brush)
                           (send dc draw-rectangle 0 0 100 200)  ; big blue rectangle
                           (send dc set-brush yellow-brush)
                           (map
                            (lambda (y) (send dc draw-rectangle 0 y 200 1)) ; draw a line for each integer.
                            list-of-points ))
                         (draw-chart))) ; draw it for the first time when this class is instantiated

; Make a  frame
(define frame (new frame% [label "scatter-chart% Example"] [width 100] [height 200]))

; Show the frame
(send frame show #t)
; Wait a second to let the window get ready
;(sleep/yield 1)
(define new-my-widget (new scatter-chart% (parent frame) ))  ; instantiate the widget in the frame
(define new-his-widget (new scatter-chart% (parent frame) )) ; make another one

(send new-my-widget draw-chart)
; Draw the face
(define (go) 
  (map (lambda (y)
       (send new-my-widget add-point y) ; add a point at a time
         (sleep/yield 0.05)) ; draw it slowly
       '(10 30 22 77 78 79 17 65 97 54 55 56 57 91 33 55 95 99 125 155 157 159 188 187 186 191))) ;; list of datapoints

(go)  ;; !!!
-- StephenDeGabrielle - 21 Sep 2007

Contributors

-- EwanHiggs - 01 Sep 2004

CookbookForm
TopicType: Recipe
ParentTopic: GUIRecipes
TopicOrder: 030

 
 
Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest