Module 在Racket中,如何执行按钮';s回调函数,当该函数位于另一个文件中时?

Module 在Racket中,如何执行按钮';s回调函数,当该函数位于另一个文件中时?,module,callback,scheme,lisp,racket,Module,Callback,Scheme,Lisp,Racket,在Racket中,当按钮的回调函数位于另一个文件中时,如何执行该函数 我有一个文件GUI.rkt,其中包含我的GUI代码: #lang racket/gui (提供(所有已定义) (定义主(新帧%[标签“应用”])) (新按钮%[父主][标签“单击”] [回调(lambda(按钮事件)(开始捕获)]) 我有一个主文件proj.rkt: #朗球拍 (需要“GUI.rkt”) (定义(开始捕获) ;做事 ;... ) 编译器给出一个错误,指出begin capture是未绑定的标识符 我知道这是

在Racket中,当按钮的回调函数位于另一个文件中时,如何执行该函数

我有一个文件GUI.rkt,其中包含我的GUI代码:

#lang racket/gui
(提供(所有已定义)
(定义主(新帧%[标签“应用”]))
(新按钮%[父主][标签“单击”]
[回调(lambda(按钮事件)(开始捕获)])
我有一个主文件proj.rkt:

#朗球拍
(需要“GUI.rkt”)
(定义(开始捕获)
;做事
;...
)
编译器给出一个错误,指出begin capture是未绑定的标识符

我知道这是一个未绑定的标识符,因为我没有在GUI文件中定义变量。Racket文档说明了如何在对象定义中设置回调函数,但不在定义之外。理想情况下,我希望从GUI访问另一个文件中的函数,以便所有GUI代码都在GUI.rkt文件中。

如果
“GUI.rkt”
需要
“proj.rkt”
中的标识符,然后
“proj.rkt”
需要
提供它们,而
“GUI.rkt”
需要
需要
“proj.rkt”
,而不是相反。如果这两个模块需要彼此的标识符,那么您几乎肯定会遇到设计问题

如果您希望程序的GUI部分是其他部分所要求的,那么一个明显的方法是it提供过程,使其采用回调之类的参数:

(provide
 ...
 make-main-frame
 ...)

(define (make-main-frame ... capture-callback ...)
  (define main (new frame% [label "App"]))
  (new button% [parent main] [label "Click"]
       [callback (lambda (button event) (capture-callback))])
  ...
  main)
但是,请注意,我不知道人们通常是如何使用GUI组织程序的,更不用说他们是如何在Racket中组织程序的,因为我已经很长时间没有编写这种代码了。我认为,对于任何带有模块的程序,基本的处理方法是:

  • 你希望程序的模块结构中没有循环——即使Racket的模块系统可能有循环,它们出现在程序中也会给我敲响警钟
  • 如果图中的“较低”模块(图中的某个“较高”模块正在使用
    require
    d的模块)可能需要使用该较高模块的功能,则可能应该通过提供程序来实现,该程序采用较高模块可以提供的参数,或与之等效的功能
以上两点仅是我的观点:我可能错误地认为最好的风格是球拍


一个可能的例子 这里有一种实现普通GUI的方法,即可以更改回调,但GUI代码和实现代码是隔离的

首先,gui位于
“gui.rkt”
中,如下所示:

#lang racket/gui

(provide (contract-out
          (selection-window (->* (string?
                                  (listof string?)
                                  (-> string? any))
                                 (#:initial-choice string?)
                                (object/c)))))

(define (selection-window name choices selection-callback
                          #:initial-choice (initial-choice (first choices)))
  ;; make & show a selection window for a number of choices.
  ;; selection-callback gets called with the choice, a string.
  (define frame (new frame% [label name]))
  (new choice%
       [parent frame]
       [label "state"]
       [choices choices]
       [selection (index-of choices initial-choice)]
       [callback (λ (self event)
                   (selection-callback (send self get-string-selection)))])
  (send frame show #t)
  frame)
#lang racket

(require "gui.rkt")

(define selection-callback-implementation
  (make-parameter (λ (s)
                    (printf "selected ~A~%" s))))

(selection-window "foo" '("red" "amber" "green")
                  (λ (s) ((selection-callback-implementation) s))
                  #:initial-choice "green")
因此,这提供了一个构建GUI的单一功能。在现实生活中,您可能希望提供一些附加功能来操作返回的对象,而无需此模块的用户了解它

该函数将回调函数作为参数,调用该函数的方式可能对实现有用,而不是对GUI有用(因此特别是使用所选字符串调用)

“gui.rkt”
不提供任何更改回调的方法。但这没关系:模块的用户可以这样做,例如:

#lang racket/gui

(provide (contract-out
          (selection-window (->* (string?
                                  (listof string?)
                                  (-> string? any))
                                 (#:initial-choice string?)
                                (object/c)))))

(define (selection-window name choices selection-callback
                          #:initial-choice (initial-choice (first choices)))
  ;; make & show a selection window for a number of choices.
  ;; selection-callback gets called with the choice, a string.
  (define frame (new frame% [label name]))
  (new choice%
       [parent frame]
       [label "state"]
       [choices choices]
       [selection (index-of choices initial-choice)]
       [callback (λ (self event)
                   (selection-callback (send self get-string-selection)))])
  (send frame show #t)
  frame)
#lang racket

(require "gui.rkt")

(define selection-callback-implementation
  (make-parameter (λ (s)
                    (printf "selected ~A~%" s))))

(selection-window "foo" '("red" "amber" "green")
                  (λ (s) ((selection-callback-implementation) s))
                  #:initial-choice "green")

现在,参数
选择回调实现
本质上就是回调,可以进行调整以改变它是什么。当然,如果您愿意,您可以不使用参数来实现这一点,但我认为参数是一种很好的方法(尽管,可能是取消回调).

那么,如果有一个GUI工具包,要求您修改代码结构以满足序列要求,那又有什么用呢?GUI构建者会将代码生成到一个文件中,然后建议将GUI包含在一个带有(require)的主.rkt文件中。我不希望GUI构建器为GUI元素生成回调设置器。@Ryan:我只知道模块系统。我发现在Racket中编写玩具GUI很容易,可以很好地与之配合,但我是通过自己编写代码来做到这一点的:我想任何GUI构建工具都会附带一个关于如何为其代码解决这些问题的指南nerates?我遵循了官方的指南。也许我在浏览文档以探索GUI元素的字段和方法之前做得不够。似乎我需要的概念是“包装器”函数。我用
GUI.rkt
文件中的
setter
getter
函数包装GUI和对象库的函数,并将这些函数公开给main.rkt。然后传递函数指针(对函数的引用)到我的
main.rkt
文件中的setter或getter函数。这为我的GUI.rkt文件创建了一种接口供main.rkt使用。我希望能够根据main.rkt中的事件和逻辑设置回调。现在我已经仔细考虑了这一点,我必须问,我是否可以通过使用
(define>)创建setter函数来实现这一点(btn1回调setter)
并将其提供给main.rkt(使用
(提供btn1回调setter)
以便main.rkt可以在GUI创建后分配不同的回调函数?(哦…我上面写了同样的内容)。@Ryan:感谢您提供的具体示例:我将在今天晚些时候添加一个示例,说明我认为您可以如何做到这一点(刚才很忙,对不起!)