Возврат информации с кнопок в clojure/seesaw
У меня есть еще один сомнительный вопрос.
Сейчас я работаю над проектом и пытаюсь написать для него GUI-компонент. У меня все функциональные части работают, так что теперь я просто хочу, чтобы он тоже выглядел красиво и узнал немного больше о том, как работает качели.
По сути, у меня есть несколько полей ввода (например, текстовые поля, ползунки, поля со списком), которые пользователь может использовать для ввода определенных типов данных. Когда пользователь нажимает кнопку "Подтвердить", я хочу, чтобы действие кнопки вернуло все значения вышеупомянутых полей ввода. У меня нет большого опыта работы с потоками, но я понимаю, что (очевидно) могут быть некоторые проблемы с параллелизмом. Как я могу сделать это?
Для справки, вот небольшой пример моего кода:
;
;in restaurant-gui.core
;
(defn window-setup []
(let [my-font (font :name "Arial"
:size 22)
cuisine-label (label :text "Cuisine: "
:font my-font
:border [20 10])
cuisine (combobox :model["Any cuisine"
"American"
"Barbecue"
"Chinese"
"French"
"Italian"])
confirm-button (button :text "Confirm"
:listen [:action (fn [event] event
(selection cuisine))])
window-contents (vertical-panel :items [cuisine-label cuisine
confirm-button])]
window-contents))
;
;in restaurant-inference-engine.core
;
(defn -main
[&args]
(binding [window-contents (window-setup)]
(draw-window window-contents) ;somehow listen here for
;information from the button
;and bind it to button-info?...
(search-for-restaurant button-info)))
Кроме того, если кто-нибудь знает какой-либо простой или промежуточный код clojure, на который я мог бы взглянуть, я был бы очень благодарен. Я хотел бы получить больше информации о хорошо написанном коде clojure, чтобы улучшить мое понимание языка.
1 ответ
При работе с такими неотъемлемыми состояниями, как GUI, часто бывает полезно обратиться к изменяемым функциям Clojure. Я видел два основных подхода:
- хранить состояние каждого элемента пользовательского интерфейса в
ref
а затем передать соответствующие ссылки в функции, которые должны работать в состоянии пользовательского интерфейса. - хранить состояние графического интерфейса в одном
atom
и передать этот атом каждой функции, которая использует любые компоненты пользовательского интерфейса, чтобы они всегда могли использовать текущее состояние пользовательского интерфейса в любое время. Будьте осторожны, чтобы обновить его в согласованном порядке. - используйте core.async, чтобы события пользовательского интерфейса отправляли сообщения тем компонентам, которые в них нуждаются. Это позволяет очень отзывчивым интерфейсам с, на мой взгляд, чистым кодом, хотя вы должны выполнить настройку каналов.
Кажется маловероятным, что какой-либо из них будет работать для всех или даже для большинства проектов, так что некоторые из них имеют отношение к тому, как будет выглядеть ваш конкретный проект. Вероятно, вам не нужно беспокоиться о проблемах "параллелизма", если вы придерживаетесь официальных методов Clojure для работы с изменяющимся состоянием (атомов. Переменные, агенты, чаны).