[racket] Run Code after Button Click using the racket/gui library

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Mon Oct 27 13:56:38 EDT 2014

On Oct 26, 2014, at 5:51 PM, Derek C. wrote:

> I am trying to get the value of a label after a button is clicked. I know that I can use (send x get-label) to get the value of the label, but it only gets the initial value of the label in my case "No Zip Code Entered".

I don't know what you are asking. When I enter a zip code and click Submit, the zip code shows up in your text field. 


> Also, after that button is pressed I would like to run code that queries an API and parses xml information using the zip code from the label. Below is my code:

See below. I have marked some small changes and sketched a way to get this going. I also fixed some basic style issues. 

Note: if this is homework, please forward the assignment so we can help more directly. If not, I recommend developing with testing in mind (see rackunit and submodules). 

-- Matthias





#lang racket

(require racket/gui/base)

;; -> Void 
(define (main) ;; don't run directly, wrap in main function from the beginning; work with (module+ main ...) if you want to always run 
  
  ;; Creates a Frame called mainframe
  (define mainframe 
    (new frame%
         [label "Forecaster - Powered by Wunderground API"]
         [width 500]
         [height 500]
         [stretchable-width 500]
         [stretchable-height 500]))
  
  ;; Creates a Current Conditions group-box-panel
  (define maingroup
    (new group-box-panel%
         [label "Current Conditions:"]
         [parent mainframe]
         [min-height 450]
         [stretchable-height 450]))
  
  (define cclabel-text (new text%)) ; you want a editor here, not a message 
  [send cclabel-text insert "Insert Conditions Here from API"] ;; add your initial string, though I am not sure what for 
  (define cclabel  ;; now put the editor into a canvas
    (new editor-canvas%
         [parent maingroup]
         [label "current conditions"]
         [editor cclabel-text]))
  
  ;; Creates a Zip Code group-box-panel
  (define zipcodegroup 
    (new group-box-panel%
         [label "Zip Code:"]
         [parent mainframe]
         [min-height 100]
         [stretchable-height 100]))
  
  ;; Zip Code Message Label -- Defaults to No Zip Code Entered
  (define zipcodelabel
    (new message%
         [parent zipcodegroup]
         [label "No Zip Code Entered"] ))
  
  ;; Zip Code Text-Field
  (define zipInput 
    (new text-field% 
         [parent zipcodegroup]
         [label ""]
         [init-value ""]
         [min-width 5]
         [stretchable-width 5]
         [callback
          (lambda(f ev)
            (define v (send f get-value))
            (unless (string->number v)
              (send f set-value (regexp-replace* #rx"[^0-9]+" v ""))))]))
  
  ;; Submit Button
  (define submit-button 
    (new button% 
         [parent zipcodegroup]
         [label "Submit"]
         [callback  
          (lambda (button event)
            ;; use internal define over let only because it's easier
            (define zip-code (send zipInput get-value))
            (define weather  (retrieve zip-code))
            (send zipcodelabel set-label zip-code)
            ;; now insert weather into the editor, but clear it first 
            (send cclabel-text select-all)
            (send cclabel-text clear)
            (send cclabel-text insert (prepare-as-text weather)))]))
  ;; -- IN -- 
  (send mainframe show #t))  

;; helper but this may actually have to work on the editor directly to make it look good 
(define (prepare-as-text list-of-pairs)
  (string-join 
   (map (lambda (x) (format "~a ~a" (first x) (second x))) list-of-pairs)
   "\n"))

;XML Parsing:
;
;#lang racket

;; this module should presumably provide a retrieve function that does the hard work: 
;; (provide 
;;    ; ZipCode -> [Listof [List Symbol String]]
;;    ; retrieve the information for the given zip code and deliver the result as an association list 
;;    ; -- examples here -- 
;;    retrieve)
(require net/url xml xml/path)

(define underground-url-format
  "http://api.wunderground.com/api/*snip*/conditions/q/autoip.xml")

;; I am taking a short-cut here: 
(define (retrieve zip-code)
  (list (list 'Location: "Boston, MA") (list 'Conditions: "typical fall day") 
        (list 'Temperature: "57o F")   (list 'Feels-Like: "damp, humid, earthy")
        (list 'Humidity: "67%")        (list 'Wind: "5mph, south-by-south-west")))

(define (retrieve-to-be-done zip-code)  
  (define curent-cond-url (string->url (format underground-url-format zip-code)))
  (define current-cond-port (get-pure-port curent-cond-url))
  (define response (port->string current-cond-port))
  (close-input-port current-cond-port)
  
  (define data (xml->xexpr
                ((eliminate-whitespace '(response))
                 (read-xml/element (open-input-string response)))))
  
  (define curr-location (se-path*/list '(display_location full) data))
  (define curr-weather (se-path*/list '(current_observation weather) data))
  (define curr-temp (se-path*/list '(current_observation temp_f) data))
  (define curr-humidity (se-path*/list '(current_observation relative_humidity) data))
  (define curr-wind (se-path*/list '(current_observation wind_string) data))
  (define curr-feels-like (se-path*/list '(current_observation feelslike_f) data))
  
  (list (list 'Location: curr-location) (list 'Conditions: curr-weather) 
        (list 'Temperature: curr-temp)  (list 'Feels-Like: curr-feels-like)
        (list 'Humidity: curr-humidity) (list 'Wind: curr-wind)))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20141027/e511373b/attachment.html>

Posted on the users mailing list.