Racket 编程
第 3 部分 · GUI 开发

GUI 开发入门

GUI 开发入门

使用 racket/gui 库创建跨平台的桌面应用程序。

第一个窗口

#lang racket/gui

;; 创建主窗口
(define frame
  (new frame%
       [label "我的第一个 Racket GUI"]
       [width 400]
       [height 300]))

;; 创建消息面板
(define msg
  (new message%
       [parent frame]
       [label "Hello, Racket GUI!"]
       [auto-resize #t]))

;; 显示窗口
(send frame show #t)

运行这段代码,你会看到一个带有标题和文本的窗口。

添加交互控件

#lang racket/gui

(define frame
  (new frame%
       [label "交互示例"]
       [width 400]
       [height 200]))

;; 文本输入
(define input
  (new text-field%
       [parent frame]
       [label "输入名字:"]))

;; 按钮
(define btn
  (new button%
       [parent frame]
       [label "打招呼"]
       [callback
        (lambda (button event)
          (define name (send input get-value))
          (message-box "问候"
                       (format "你好, ~a!" name)
                       frame))]))

(send frame show #t)

布局管理

使用水平和垂直面板组织控件:

#lang racket/gui

(define frame
  (new frame%
       [label "布局示例"]
       [width 500]
       [height 400]))

;; 垂直面板
(define vpanel
  (new vertical-panel%
       [parent frame]
       [alignment '(center center)]))

;; 水平面板
(define hpanel
  (new horizontal-panel%
       [parent vpanel]
       [alignment '(center center)]))

;; 在水平面板中添加按钮
(new button% [parent hpanel] [label "按钮 1"])
(new button% [parent hpanel] [label "按钮 2"])
(new button% [parent hpanel] [label "按钮 3"])

;; 下方添加一个画布
(define canvas
  (new canvas%
       [parent vpanel]
       [min-height 200]
       [paint-callback
        (lambda (canvas dc)
          (send dc set-brush "blue" 'solid)
          (send dc draw-rectangle 50 50 100 100))]))

(send frame show #t)

画布与绘图

#lang racket/gui

(define frame (new frame% [label "绘图示例"] [width 600] [height 400]))

(define my-canvas%
  (class canvas%
    (inherit get-dc)
    
    (define/override (on-event event)
      (when (send event button-down?)
        (define dc (get-dc))
        (define x (send event get-x))
        (define y (send event get-y))
        (send dc set-brush (make-object color% (random 256) (random 256) (random 256)) 'solid)
        (send dc draw-ellipse (- x 10) (- y 10) 20 20)))
    
    (super-new)))

(define canvas
  (new my-canvas%
       [parent frame]
       [paint-callback
        (lambda (canvas dc)
          (send dc set-background "white")
          (send dc clear))]))

(send frame show #t)

点击画布任意位置,会绘制一个随机颜色的圆形。

菜单和对话框

#lang racket/gui

(define frame (new frame% [label "菜单示例"] [width 400] [height 300]))

;; 菜单栏
(define menu-bar (new menu-bar% [parent frame]))

;; 文件菜单
(define file-menu (new menu% [label "文件"] [parent menu-bar]))

(new menu-item%
     [label "打开..."]
     [parent file-menu]
     [callback
      (lambda (m e)
        (define path (get-file))
        (when path
          (printf "选择了文件: ~a\n" path)))])

(new separator-menu-item% [parent file-menu])

(new menu-item%
     [label "退出"]
     [parent file-menu]
     [callback (lambda (m e) (send frame show #f))])

;; 帮助菜单
(define help-menu (new menu% [label "帮助"] [parent menu-bar]))

(new menu-item%
     [label "关于"]
     [parent help-menu]
     [callback
      (lambda (m e)
        (message-box "关于" "Racket GUI 示例程序 v1.0"))])

(send frame show #t)

事件处理模型

Racket GUI 使用回调函数处理事件:

事件类型触发条件
button%按钮点击
text-field%文本变化
canvas%鼠标/键盘交互
timer%定时触发
;; 定时器示例
(define timer
  (new timer%
       [interval 1000]  ; 每秒触发一次
       [notify-callback
        (lambda ()
          (printf "Tick: ~a\n" (current-seconds)))]))

打包应用

使用 raco exe 将 Racket GUI 程序打包为可执行文件:

# 创建可执行文件
raco exe --gui my-app.rkt

# 生成独立分发的目录
raco dist my-app-dist my-app.exe

这样生成的应用可以在没有 Racket 运行时的机器上运行。