Clojure2D / clojure2d-examples

Examples for Clojure2d
Eclipse Public License 1.0
88 stars 8 forks source link

Question: close window from within key-typed handler? #5

Open pmonks opened 3 years ago

pmonks commented 3 years ago

Apologies if there's better forum for questions, but I've been banging my head on this for a little while and haven't figured it out yet.

Basically I want any press of the 'q' key to close the window the key was pressed in. I've registered a key-typed handler as follows:

(defmethod c2d/key-typed [window-name \q]
  [event state]
  (comment "What goes here? 🤔"))

And verified that it's called correctly, but I'm at a loss as to how to close the window.

Both of the solutions I thought of (adding a quit-requested flag to the window's state) or just calling c2d/close-window directly require a handle to the window (returned by c2d/show-window), which I don't have here, and I haven't yet figured out if/how to obtain a handle to the window from the event object (despite a bit of digging through the Java object model reachable from the event).

Is it possible to obtain the window object from the event object? Or am I going to have to store the window in a global somewhere (i.e. an atom) and hardcode the handler to refer to it (which I'd like to avoid, if at all possible)?

genmeblog commented 3 years ago

Hi! Indeed there is no way to map window name to a window. So currently the only way is to keep window object externally. Anyway, I'll try to figure out how to pass window object to the events or will create global registry to allow using name in functions where window is needed. Great issue, thanks!

pmonks commented 3 years ago

Thanks @genmeblog. Couple of follow up thoughts / questions:

  1. Am I right in thinking that window names are not unique, and so may not be suitable as an alternative to the actual window object? For example right now my app (a simple simulation) allows any number of windows to be created, and all of them have the same name.
  2. Is there any way to retrieve the Window via the event object rather than the window name? For example the event's .getSource and .getComponent methods return a java.awt.Canvas object - is there some way to determine which window that canvas is associated with, through the Java object graph and/or AWT / Java2D APIs?
genmeblog commented 3 years ago

Thanks.

Ad.1. Window names are unique (https://github.com/Clojure2D/clojure2d/blob/26cceb14982a30fa6f867a5e5bf120f270c2b170/src/clojure2d/core.clj#L2106) Ad.2. Window handler is a custom type so no way to make it a component or source (from the awt point of view). The only way I could assign was a string. Maybe I'm wrong here and need to play more. Anyway the best would be a public registry mapping name and handler.

pmonks commented 3 years ago

A1 - window names may default to being unique if not provided, but AFAIK they're not required to be unique. For example, my simulation used to hardcode the names of all windows to a constant value [1], and functioned just fine I just noticed that the states ended up clobbering each other (there ended up being only one state shared by all windows, despite there initially being a different state per window).

I've since switched to unique window names and a window registry, which isn't perfect as I can't dissoc windows from it when the OS' native "close window" UI affordance is used (I couldn't find an event to respond to in that case).

It may be useful to internalise a registry such as this within Clojure2D, and provide both automatic addition/removal of entries in that registry, as well as queries that allow user code to look it up (i.e. find a window object by window name).

[1] https://github.com/pmonks/gravity/blob/c921e813ae4e729703c2c70f7c7f5767ee8e7fd3/src/gravity/gui.clj#L55