You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DrRacket银行用户GUI开发:账号数据存储与加载问题求助

问题修复与解决方案

1. 修复string-blank?报错

Racket没有内置的string-blank?函数,你可以通过两种方式解决:

方法一:自定义string-blank?函数

先导入字符串处理库,再实现判断逻辑:

(require racket/string)

(define (string-blank? s)
  (string=? (string-trim s) ""))

方法二:直接替换判断逻辑

修改load-users-from-file中的空内容判断:

(data (if (string=? (string-trim content) "")
          '()
          (string->jsexpr content)))

2. 修正json->user参数缺失问题

你的user结构体包含userPhone字段,但json->user构造时漏掉了这个参数,导致初始化错误,修改后:

(define (json->user json-data)
  (user
   (cdr (assoc "userID" json-data))
   (cdr (assoc "userType" json-data))
   (cdr (assoc "userName" json-data))
   (cdr (assoc "userEmail" json-data))
   (cdr (assoc "userPhone" json-data))  ; 补上userPhone参数
   (cdr (assoc "userPassword" json-data))))

3. 修复用户ID重复问题

原代码中user-id-counter不会根据已加载用户更新,导致新增用户ID重复,加载数据后需要同步计数器:

(load-users-from-file "users.json")

; 加载完成后更新ID计数器
(when (not (hash-empty? userAccount))
  (define max-id (apply max (map (lambda (u) (string->number (user-userID u))) (hash-values userAccount))))
  (user-id-counter (add1 max-id)))

更稳妥的方式是把userID设为数字类型,避免字符串转数字的麻烦:

(struct user (userID userType userName userEmail userPhone userPassword) #:mutable)
(define user-id-counter (make-parameter 1))

(define (generate-user-id) 
  (define id (user-id-counter)) 
  (user-id-counter (add1 id)) 
  id)

; 加载后更新计数器
(when (not (hash-empty? userAccount))
  (user-id-counter (add1 (apply max (map user-userID (hash-values userAccount))))))
完整功能实现思路

1. 数据存储层(已完成核心逻辑)

  • 用JSON文件持久化用户数据,保证重启程序后数据不丢失
  • 哈希表userAccount作为内存缓存,以邮箱为键实现用户快速查找
  • 封装save-users-to-file和load-users-from-file,保证内存数据与文件数据一致

2. GUI界面实现

需要搭建登录、注册两个核心界面,基于racket/gui/base组件实现:

登录界面

  • 创建窗口、垂直布局面板
  • 添加邮箱输入框、密码输入框(设置#:password? #t隐藏输入内容)
  • 登录按钮点击时调用find-user验证,根据结果弹出提示框

注册界面

  • 包含用户名、邮箱、手机号、密码输入框
  • 注册按钮点击时校验输入合法性(如非空),创建user实例并调用add-user!保存
  • 添加界面切换按钮,实现登录/注册窗口的互相跳转

示例GUI代码片段:

; 登录窗口
(define login-frame (new frame% [label "银行系统登录"] [width 300] [height 200]))
(define login-panel (new vertical-panel% [parent login-frame] [alignment '(center center)] [spacing 10]))

(new message% [parent login-panel] [label "邮箱"])
(define login-email-field (new text-field% [parent login-panel] [init-value ""]))

(new message% [parent login-panel] [label "密码"])
(define login-pwd-field (new text-field% [parent login-panel] [init-value ""] [password? #t]))

(new button% [parent login-panel] [label "登录"]
     [callback (lambda (button event)
                 (define email (send login-email-field get-value))
                 (define pwd (send login-pwd-field get-value))
                 (define u (find-user email pwd))
                 (if u
                     (message-box "成功" (string-append "欢迎你," (user-userName u)))
                     (message-box "错误" "邮箱或密码不正确")))])

(new button% [parent login-panel] [label "注册账号"]
     [callback (lambda (button event)
                 (send login-frame show #f)
                 (send register-frame show #t))])

; 注册窗口
(define register-frame (new frame% [label "银行系统注册"] [width 300] [height 300] [show #f]))
(define register-panel (new vertical-panel% [parent register-frame] [alignment '(center center)] [spacing 10]))

(new message% [parent register-panel] [label "用户名"])
(define reg-name-field (new text-field% [parent register-panel] [init-value ""]))

(new message% [parent register-panel] [label "邮箱"])
(define reg-email-field (new text-field% [parent register-panel] [init-value ""]))

(new message% [parent register-panel] [label "手机号"])
(define reg-phone-field (new text-field% [parent register-panel] [init-value ""]))

(new message% [parent register-panel] [label "密码"])
(define reg-pwd-field (new text-field% [parent register-panel] [init-value ""] [password? #t]))

(new button% [parent register-panel] [label "注册"]
     [callback (lambda (button event)
                 (define name (send reg-name-field get-value))
                 (define email (send reg-email-field get-value))
                 (define phone (send reg-phone-field get-value))
                 (define pwd (send reg-pwd-field get-value))
                 (if (or (string-blank? name) (string-blank? email) (string-blank? phone) (string-blank? pwd))
                     (message-box "错误" "请填写所有字段")
                     (begin
                       (define new-u (user (generate-user-id) "personal" name email phone pwd))
                       (add-user! new-u)
                       (message-box "成功" "注册成功,请登录")
                       (send register-frame show #f)
                       (send login-frame show #t))))])

(new button% [parent register-panel] [label "返回登录"]
     [callback (lambda (button event)
                 (send register-frame show #f)
                 (send login-frame show #t))])

; 显示登录窗口
(send login-frame show #t)
学习资源推荐

书籍

  • Racket Programming the Fun Way:入门级书籍,涵盖Racket基础语法、GUI开发、数据处理,适合快速上手
  • Realm of Racket:以游戏开发为载体,讲解Racket核心概念,包括GUI、函数式编程
  • Racket Guide:官方指南文档,系统介绍Racket所有核心特性,包含racket/gui/base的详细用法

视频教程

  • Racket官方YouTube频道GUI系列教程:官方出品,讲解GUI组件基本使用与界面布局
  • Racket入门到进阶系列视频:覆盖基础语法、函数式编程、GUI开发,适合逐步深入学习

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:24:51