In Racket's GUI library, I can use a text-field% to add a single line textbox to a window. However, I would like to limit this text box to only allow integers to be typed.
One possible way to handle this is to insert a callback whenever a letter is typed, to add it into the text box ourselves. The text-field% class has methods get-value and set-value, but there are only used for programmatic modification of the text box, and not as a callback.
Another way would be to pass in a regex for allowable characters or strings in the text box, but this does not seem to be supported either.
So, is there any way to create a text field in Racket that will only allow the user to type in integers?
It would appear that there already is a solution to this problem on Rosetta Code. What you 'can' do in a text box is set a callback that is called whenever the user types. Then, you can use set-value to remove the character that you didn't want there. The resulting text-field% object would look like this (taking it from the link):
(new text-field% [label "Value"] [parent frame] [init-value "0"]
[callback
(λ (f ev)
(define v (send f get-value))
(unless (string->number v)
(send f set-value (regexp-replace* #rx"[^0-9]+" v ""))))]))
Where frame is the frame you are putting in the text box, say:
(define frame (new frame% [label "Demo Frame"))
Related
Racket programs that use racket/gui run until all of the windows are closed. This makes it easy to write a program like:
#lang racket/gui
(define window (new frame% [label "Hello"] [width 100] [height 100]))
(send window show #t)
And now the program will continue to run until the window is closed.
However, it sometimes makes sense to close a window programmatically, for example, if I want a countdown that will close the window and finish after the countdown is done.
As far as I can tell though, the only way to 'close' a window is the show method:
(send window show #f)
This however only stops the window from being displayed, but does not actually close the window. Normally, this is good enough and the program exits, like in this example:
#lang racket/gui
(define window (new frame% [label "hello"]))
(send window show #f)
However, if the program has a timer, it will not exit until the timer finishes. You can set a callback in the window on-close, but this is only called when the window is actually closed, not when its hidden with show. For example, this program will not get stuck:
#lang racket/gui
(define window
(new (class frame%
(super-new [label "hello"])
(define timer
(new timer%
[interval 1000]
[notify-callback (λ x (displayln "ding"))]))
(define/augment (on-close)
(send timer stop)))))
(send window show #f)
So, is there a way to either figure out when a window is hidden (via the show) function or programmatically close the window? If neither is the case, is overwriting the show method to stop the timer myself a bad idea?
Since you are subclassing the frame% class anyway, you can override the show method1 to stop the timer whenever the window is closed. (Do remember to restart it when the window reopens if that is important to you.)
(define/override (show show?)
(unless show?
(send timer stop))
(super show show?))
Making your overall class look something like:
#lang racket/gui
(define window
(new (class frame%
(super-new [label "hello"])
(define timer
(new timer%
[interval 1000]
[notify-callback (λ x (displayln "ding"))]))
(define/augment (on-close)
(send timer stop))
(define/override (show show?)
(unless show?
(send timer stop))
(super show show?)))))
(send window show #f)
Now your program will terminate.
1There is a on-superwindow-show method, but it does not seem to always run when show is called.
I wonder if my drRacket has a problem :
I see example on the internet of programs but when I put them in Dr racket, it considers them as an error.
It first append when I write (require racket/base) at the begining of a new file. It immediately consider it like an error. So I replace it with #lang racket/base and it was ok but it is strange, I still don't know why it doesn't work.
Then, I try to use this command : (define FRAME (new frame% [label "Graphic"] [width 500] [height 500]))
but it show me a new error : new: unbound identifier in module in: new.
This time I am unable to find something that work to show me my graphic :(
I dont't get it : why when I copy-past program that work on the net, they don't whant to whork whith me? It is really frustrating. I download the last version of the programme (version 5.3.3) and it does not solve my problem.
Anybody can explain it work with other person but it don't work with me? Or maybe tell me how to do my graphic?
First I'd suggest you start every program with just
#lang racket
since this gives you the full base of the Racket language. Also make sure DrRacket is set to "determine language from source" (bottom left on Mac OS X).
Nevertheless some things need to be imported. If you look up new in the docs, for example, it is provided by racket/class or racket, not by racket/base, which explains the message you get.
frame% is provided by racket/gui or racket/gui/base, so finally this will work:
#lang racket
(require racket/gui)
(define FRAME (new frame% [label "Graphic"] [width 500] [height 500]))
The example you copy-pasted probably included the require statement.
Try to get comfortable with reading the Racket docs, they are well written and searchable.
I want to make an executable file for the following code.
This is scheme written in Dr.racket.
How would this be done?
It would be best if it can be stand-alone and if I can open it in on iOS and Windows.
Thank you very much for your time!
#lang racket
(require racket/gui/base)
(require compiler/embed)
; Make a frame by instantiating the frame% class
(define frame (new frame% [label "GUI"]
[width 200]
[height 200]))
; Make a static text message in the frame
(define msg (new message% [parent frame]
[label "This box is empty"]))
; Show the frame by calling its show method
(send frame show #t)
As pointed by #dyoo, in Racket you can create an executable from the menu and (depending on the selected/available options) pack the required libraries; read the instructions. Also you can create executables for other platforms using command line tools.
For a more general and portable solution, consider compiling the code to C first and then compile from C to a native executable; take a look at the raco tool (section 9.3), or look at a Scheme implementation designed for easily compiling to C, such as Chicken Scheme or Gambit Scheme.
Getting the code to run under iOS might be trickier, a quick search returned a Gambit REPL for iOS, give it a try but I don't think there's support for compiling to native Objective-C code, although Gambit claims to have "full integration support for C++ and Objective-C compilers", you'll have to experiment with it a bit.
Finally, notice that GUI code specific to Racket (like the one in the question) will almost certainly be non-portable across different Scheme implementations/platforms...
Using racket gui library, I find I can't a real modal dialog that when it's showed, it's impossible to activate its parent window.
Although the dialog will block its parent's eventspace, the menu bar in parent window can be clicked, and thus the same dialog can be showed again and again. Following is the code:
#lang racket/gui
(define frame (new frame%
[label "test"]
[width 200]
[height 200]))
(define mb (new menu-bar% [parent frame]))
(let ([m (new menu%
[parent mb]
[label "&About"])])
(new menu-item%
[parent m]
[label "&About"]
[callback (lambda (b e) (message-box "About" "This is a test." frame))])
)
(send frame show #t)
(p.s the message-box can pop up a dialog - the same as (new dialog% [parent frame]))
So if we ignores the first question, can we show a modal dialog that disables parent's menu bar?
Besides, is it really impossible to make a real modal dialog in racket/gui?
(I'm working on Win7)
Followup: it was a bug, and will be repaired.
References:
http://lists.racket-lang.org/users/archive/2012-April/051275.html
http://git.racket-lang.org/plt/commit/9d563c786a71b621fcd2909c917b49939e0d11b0
Instead of using a frame%, I think you want to use a dialog% class here. I'm not sure that you can make a modal dialog that has a menu bar easily though.
Oh, also keep in mind that dialog% is only modal for its eventspace. So if you run a code snippet from DrRacket that creates a dialog, then DrRacket itself will still be accessible.
This seems a bit hackish, but you could do it yourself with [callback (lambda (b e) (send mb enable #f) (message-box "About" "This is a test.") (send mb enable #t))] Or perhaps use dynamic-wind if continuations are involved, which in your example they're not.
Or the basic work need to do to create a GUI. I know the basic Components
of GUI, but where to begin. I'm just a self-study person and I'm reading "How to Design Program" (HtDP) at the end of the book the author suggest that knowledge of GUI and CGI computer network are needed to be a programmer. The information of the last two is easy to find. But it seems there are little book talking about how to create a GUI. I guess maybe it's too "low" in the process designing the computer program that few people even care.
The documentation for GUI programming in DrRacket (the name of current versions of DrScheme) is here: http://docs.racket-lang.org/gui/index.html
Since you're reading HTDP, this is probably the best option for you right now.
If you want to just make the simple GUI in Common Lisp, your best
choice, in my opinion, is LTK, which is a high-level interface to
Tcl/Tk scripting library
There are plenty of other choices, but they require some
vision of what you are trying to achieve. If you want to use
one of the wide-spread GUI toolkits (GTK or Qt) there are CL-GTK2
and CommonQt. But you have to first of all understand well, how these
toolkits work
LispWorks provides a very sophisticated GUI-builder library CAPI,
which is cross-platform
On the Mac ClozureCL has good Cocoa bindings
Finally there's a full-blown native CL solution for GUI - McCLIM -
which is very flexible, but pretty involved
Also, if you want to understand GUI and study it from the theoretical point of view, you should learn about various GUI-patterns, such as MVC, Model2, MVVM etc. I don't know about any GUI-framework in Lisp, implementing such patterns, so doing such a project may be an interesting learning experience...
There's a lightweight library for writing simple graphical programs through 2htdp/universe. See: How to Design Worlds.
The basic idea is that modern graphical libraries are highly event-driven: you interact with the external world by responding to events. If you look at it closely enough, the universe library is an implementation of the MVC model: the world is the "Model", the to-draw the "View", and all the other event handlers the "Controller".
If you want to work with more low-level elements in Racket, you can use the racket/gui libraries. These have reference documentation in The Racket Graphical Interface Toolkit. Here's a small example that uses the library:
#lang racket
(require racket/gui/base
2htdp/image
(only-in mrlib/image-core render-image))
;; The state of our program is a number.
(define state 0)
;; On a timer tick, increment the state, and refresh the canvas.
;; tick!: -> void
(define (tick!)
(set! state (add1 state))
(send THE-CANVAS refresh))
;; When a canvas paints itself, use the following:
;; paint: canvas% dc<%> -> void
(define (paint! a-canvas my-drawing-context)
(define my-new-scene (text (format "I see: ~a" state) 20 'black))
;; Note: we force the canvas to be of a particular width and height here:
(send a-canvas min-client-width (image-width my-new-scene))
(send a-canvas min-client-height (image-height my-new-scene))
(render-image my-new-scene my-drawing-context 0 0))
;; Here, we initialize our graphical application. We create a window frame...
;; THE-FRAME: frame%
(define THE-FRAME (new (class frame%
(super-new)
;; When we close the frame, shut down everything.
(define/augment (on-close)
(custodian-shutdown-all (current-custodian))))
[label "Example"]))
;; and add a canvas into it.
;; THE-CANVAS: canvas%
(define THE-CANVAS (new (class canvas%
(super-new)
;; We define a key handler. Let's have it so it
;; resets the counter on a key press
(define/override (on-char key-event)
(when (eq? (send key-event get-key-code) 'release)
(set! state 0)
(send THE-CANVAS refresh))))
[parent THE-FRAME]
[paint-callback paint!]))
;; We get the frame to show on screen:
(send THE-FRAME show #t)
;; Finally, we set up a timer that will call tick! on every second.
(define THE-TIMER (new timer%
[notify-callback tick!]
[interval 1000]))
A recent article on the current state of the Common Lisp ecosystem says: CommonQt plus Qtools is the way to go nowadays.