Tienes razón. Swing es el camino a seguir, pero conectar todas las piezas puede ser un poco difícil si estás aprendiendo Clojure y Swing. Hay algunos ejemplos cortos que muestran cómo crear GUI simples de Swing en Clojure. Aquí hay otro pequeño ejemplo que combina una GUI simple con un objeto Timer
.
(ns net.dneclark.JFrameAndTimerDemo
(:import (javax.swing JLabel JButton JPanel JFrame Timer))
(:gen-class))
(defn timer-action [label counter]
(proxy [java.awt.event.ActionListener] []
(actionPerformed
[e]
(.setText label (str "Counter: " (swap! counter inc))))))
(defn timer-fn []
(let [counter (atom 0)
label (JLabel. "Counter: 0")
timer (Timer. 1000 (timer-action label counter))
panel (doto (JPanel.)
(.add label))]
(.start timer)
(doto (JFrame. "Timer App")
(.setContentPane panel)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.setLocation 300 300)
(.setSize 200 200)
(.setVisible true))))
(defn -main []
(timer-fn))
Cuando se ejecuta, se creará una pequeña ventana con una etiqueta que se actualiza cada segundo. Según su descripción, cambiaría la frecuencia del temporizador de 1,000 ms a 300,000 ms para activar una acción cada 5 minutos. Para hacer algo más que actualizar una etiqueta, cambiaría el contenido de la función timer-action
.
I think esto es seguro para subprocesos, pero no lo he comprobado con certeza. Hay precauciones y tutoriales sobre la seguridad de los hilos cuando también se actualizan los componentes Swing. Probablemente también quieras verificarlos.
Espero que esto sea lo suficientemente informativo como para darle algunas pistas sobre dónde buscar más información.
EDIT: Quería señalar una cosa más interesante aquí.Tenga en cuenta que la función 'timer-action' está cambiando el valor de uno de sus argumentos. El argumento 'contador' es un átomo definido en 'timer-fn', sin embargo, el oyente de acción puede cambiarlo. Esto es algo que generalmente no puedes hacer en Java. Tal vez alguien más inteligente que yo pueda comentar si esto constituye un "cierre". En mi experiencia previa con lenguajes como Pascal, yo diría que el argumento que pasa es "llamada por referencia" en oposición al estricto argumento de "call-by-value" de Java. ¿Es esto algo diferente?
EDIT 2: Después de comprobar mis hechos con otra pregunta, esto es, de hecho, un ejemplo de un cierre en Clojure.
+1 para sugerir alternativas. – trashgod
Buen comienzo, pero te perdiste por completo el sube y baja (https://github.com/daveray/seesaw), que parece que hará que el desarrollo de la aplicación sea mucho menos doloroso en Clojure. – deterb