Ракетка GUI: как ссылаться на виджеты, созданные динамически во время выполнения? - PullRequest
1 голос
/ 26 февраля 2020

Это первый раз, когда я использую Racket GUI, и я должен сказать, что я действительно запутался.

У меня есть следующие требования:

  1. окно, состоящее из нескольких виджетов
  2. состояние виджетов должно меняться в зависимости от действий пользователя
  3. возможно иметь несколько экземпляров этих windows одновременно

Из-за (3) Я создал функцию create-window, которая создает новое окно с новыми виджетами. Но из-за этого у меня нет глобальной переменной для ссылки на мои виджеты.

Как ссылаться на виджеты, созданные динамически во время выполнения?

Как организовать код GUI в идиоматизме c Ракетка GUI стиль?

1 Ответ

2 голосов
/ 26 февраля 2020

Это зависит от того, где должна быть ссылка. С кем нужно разговаривать?

Например, если один виджет имеет обратный вызов другого виджета в том же фрейме, и если вы создаете оба виджета вместе, вы можете просто назвать их и получить обратный вызов замыкание ссылается на правильное имя (ie, переменная). Вот небольшой пример программы:

#lang racket/gui

;; create-hello-window : -> Void
(define (create-hello-window)
  (define f (new frame% (label "Example") (width 600) (height 400)))
  (define t (new text%))
  (define ec (new editor-canvas% (parent f) (editor t)))
  (define b (new button% (parent f) (label "Say hello")
                 (callback (lambda (b ce) (say-hello t)))))
  (send f show #t)
  (void))

;; say-hello : Editor -> Void
(define (say-hello t)
  (send t set-position (send t last-position))
  (send t insert "Hello world!\n"))

;; Create two independent hello windows
(for ([i 2]) (create-hello-window))

Обратите внимание, что обратный вызов кнопки ссылается на локальную переменную t (редактор).

Для более сложной связи вам нужно где-то сохранить ссылки к объектам, которые вы хотите сослаться. Вот еще одна версия предыдущей программы, где windows организованы в группы, и в каждом окне есть кнопка, которая записывает приветствие другому windows в группе. Группа управляет списком windows и их редакторами.

#lang racket/gui

;; A HelloWin is (hellowin Editor Frame)
(struct hellowin (editor frame))

;; A HelloGroup is (hellogroup String (Listof HelloWin))
(struct hellogroup (name [wins #:mutable]))

;; create-hello-window : HelloGroup -> Void
(define (create-hello-window group)
  (define f
    (new frame% (label (hellogroup-name group)) (width 600) (height 400)))
  (define t (new text%))
  (define ec (new editor-canvas% (parent f) (editor t)))
  (define hi-b
    (new button% (parent f) (label "Say hello")
         (callback (lambda (b ce) (add-to-end t "Hello world!\n")))))
  (define greet-b
    (new button% (parent f) (label "Greet others in group")
         (callback (lambda (b ce) (greet-everyone-else t group)))))
  (send f show #t)
  (set-hellogroup-wins! group (cons (hellowin t f) (hellogroup-wins group))))

;; add-to-end : Editor String -> Void
(define (add-to-end t str)
  (send t set-position (send t last-position))
  (send t insert str))

;; greet-everyone-else : Editor HelloGroup -> Void
(define (greet-everyone-else my-t group)
  (for ([h (in-list (hellogroup-wins group))])
    (define t (hellowin-editor h))
    (unless (equal? t my-t)
      (add-to-end t (format "~a, hello from another window!\n"
                            (hellogroup-name group))))))

;; Create two groups, and create windows for each group.

(define group1 (hellogroup "Group 1" null))
(for ([i 3]) (create-hello-window group1))

(define group2 (hellogroup "Group 2" null))
(for ([i 2]) (create-hello-window group2))

Мой код не использует hellowin-frame, но вы можете использовать его для написания процедуры, закрывающей все windows в например, группу.

Возможно, вы не хотите, чтобы группа имела прямой доступ к фрейму и его виджетам. Затем вы можете изменить протокол так, чтобы группы содержали какие-то приветственные обратные вызовы или объект (не сам виджет), реализующий определяемый вами интерфейс greetable<%>, или так далее. Тогда обратный вызов (или greetable<%> объект) будет иметь ссылки (или поля) на виджеты, но не будет представлять их непосредственно к коду группы. Также, возможно, группа должна быть объектом с методом регистрации, а не структурой с изменяемым полем.

...