Explore and drive a running JavaFX application from its Clojure REPL.
Inspection returns live JavaFX objects. Start at a node, scene, or window; omitting the starting element inspects all open windows.
Input targets a scene or window; omitting the target requires exactly one open window. Mouse positions use scene coordinates, and keyboard input goes to the scene's focused node. The desktop pointer is not moved. Mouse input requires a showing window.
Call functions directly from the REPL; thread scheduling is handled for you. Calls finish synchronously, but application work they trigger may finish later.
Example with one open window (p is the alias used in these docstrings): (require '[cljfx.plorer :as p])
;; Inspect the window and find a text field by an ID from the tree. (def window (p/one javafx.stage.Window)) (p/tree window :depth 3 :props [:id :text]) (def field (p/one window "#name")) ; replace with your field's ID
;; Click the field's center and type hi!. (p/mouse-click! window (p/point field 0.5 0.5) :primary) (doseq [key [:h :i]] (p/key-tap! window key)) (p/key-chord! window [:shift :digit1])
;; Read the result from the live object. (p/props field :only [:text])
;; Hover over a scrollable list and scroll down. (def items (p/one window "#items")) ; replace with your list's ID (p/mouse-move! window (p/point items 0.5 0.5)) (p/scroll! window (p/point items 0.5 0.5) 0 -100)
;; Take a screenshot. (p/screenshot! window)
Explore and drive a running JavaFX application from its Clojure REPL. Inspection returns live JavaFX objects. Start at a node, scene, or window; omitting the starting element inspects all open windows. Input targets a scene or window; omitting the target requires exactly one open window. Mouse positions use scene coordinates, and keyboard input goes to the scene's focused node. The desktop pointer is not moved. Mouse input requires a showing window. Call functions directly from the REPL; thread scheduling is handled for you. Calls finish synchronously, but application work they trigger may finish later. Example with one open window (p is the alias used in these docstrings): (require '[cljfx.plorer :as p]) ;; Inspect the window and find a text field by an ID from the tree. (def window (p/one javafx.stage.Window)) (p/tree window :depth 3 :props [:id :text]) (def field (p/one window "#name")) ; replace with your field's ID ;; Click the field's center and type hi!. (p/mouse-click! window (p/point field 0.5 0.5) :primary) (doseq [key [:h :i]] (p/key-tap! window key)) (p/key-chord! window [:shift :digit1]) ;; Read the result from the live object. (p/props field :only [:text]) ;; Hover over a scrollable list and scroll down. (def items (p/one window "#items")) ; replace with your list's ID (p/mouse-move! window (p/point items 0.5 0.5)) (p/scroll! window (p/point items 0.5 0.5) 0 -100) ;; Take a screenshot. (p/screenshot! window)
(all & args)Return a vector of distinct live elements matching the selectors.
Optional el is a Node, Scene, Window, or synthetic root; omission searches all open windows. Each selector searches descendants of the previous matches, excluding the starting elements. Insert > before a selector to search only direct children. With no selectors, returns [el] (the root if omitted).
Selectors:
Use > and * as unquoted clojure.core functions, not keywords or strings.
(p/all javafx.stage.Window) (p/all window "#form" > ".field") (p/all window {:text "Save"}) (p/all {:fx.plorer/class javafx.stage.Stage :title "My app"}) (p/all window {:id some? :fx.plorer/style-classes #{"primary"}})
See one to require exactly one match, props to discover property keys.
Return a vector of distinct live elements matching the selectors.
Optional el is a Node, Scene, Window, or synthetic root; omission searches
all open windows. Each selector searches descendants of the previous matches,
excluding the starting elements. Insert > before a selector to search only
direct children. With no selectors, returns [el] (the root if omitted).
Selectors:
- Java class: match instances, e.g. javafx.scene.control.Button.
- String: #id, .style-class, or combinations such as #id.primary.large.
- Function or var: predicate on the element. * matches any element.
- Map: all entries must match. Ordinary keys read props; function/var values
are predicates on a property, other values use equality (including sets).
Unsupported properties do not match, even when the expected value is nil.
:fx.plorer/class matches a class, :fx.plorer/pred tests the whole element,
and :fx.plorer/style-classes requires all listed CSS classes.
Use > and * as unquoted clojure.core functions, not keywords or strings.
(p/all javafx.stage.Window)
(p/all window "#form" > ".field")
(p/all window {:text "Save"})
(p/all {:fx.plorer/class javafx.stage.Stage :title "My app"})
(p/all window {:id some? :fx.plorer/style-classes #{"primary"}})
See one to require exactly one match, props to discover property keys.(key-chord! keys)(key-chord! el keys)Press keys in order and release them in reverse order; return nil.
el is a Window, Scene, or synthetic root; omission requires one open window. keys is an ordered collection of javafx.scene.input.KeyCodes or kebab-case keywords. Put modifiers first. Uses the virtual US keyboard; see key-press! for its rules. Use :meta for Command shortcuts on macOS, :control for Ctrl.
Input follows the scene's current focus owner. Throws if no focus owner exists; desktop focus is not required. Keys in the chord end released; other keys remain held.
(p/key-chord! window [:shift :digit1]) ; type ! (p/key-chord! window [:control :shift :z]) (p/key-chord! window [:meta :a]) ; Command+A
Press keys in order and release them in reverse order; return nil. el is a Window, Scene, or synthetic root; omission requires one open window. keys is an ordered collection of javafx.scene.input.KeyCodes or kebab-case keywords. Put modifiers first. Uses the virtual US keyboard; see key-press! for its rules. Use :meta for Command shortcuts on macOS, :control for Ctrl. Input follows the scene's current focus owner. Throws if no focus owner exists; desktop focus is not required. Keys in the chord end released; other keys remain held. (p/key-chord! window [:shift :digit1]) ; type ! (p/key-chord! window [:control :shift :z]) (p/key-chord! window [:meta :a]) ; Command+A
(key-press! key)(key-press! el key)Press a virtual US keyboard key; return the focus owner at the press.
el is a Window, Scene, or synthetic root; omission requires one open window. Input follows the scene's current focus owner; throws if none exists. key is a javafx.scene.input.KeyCode or its kebab-case keyword, e.g. :a, :digit1, :enter, :shift, :control, :meta. Pair with key-release!, or use key-tap!/key-chord! for complete sequences.
Uses a US layout regardless of the host layout. Printable keys type text unless Control, Alt, or Meta is held. Shift affects case and punctuation; :caps toggles Caps Lock for letters, with Shift reversing it. Numpad digits always type digits. Num Lock, Alt/Option character mappings, dead keys, and IME are not supported.
Keys stay held until released. Held modifiers apply to later keyboard and mouse input in the same scene. Holding a key does not repeat automatically; call again to repeat. Caps Lock toggles only once until released and pressed again.
(p/key-press! window :shift) (p/mouse-click! window [50 50] :primary) (p/key-release! window :shift)
Press a virtual US keyboard key; return the focus owner at the press. el is a Window, Scene, or synthetic root; omission requires one open window. Input follows the scene's current focus owner; throws if none exists. key is a javafx.scene.input.KeyCode or its kebab-case keyword, e.g. :a, :digit1, :enter, :shift, :control, :meta. Pair with key-release!, or use key-tap!/key-chord! for complete sequences. Uses a US layout regardless of the host layout. Printable keys type text unless Control, Alt, or Meta is held. Shift affects case and punctuation; :caps toggles Caps Lock for letters, with Shift reversing it. Numpad digits always type digits. Num Lock, Alt/Option character mappings, dead keys, and IME are not supported. Keys stay held until released. Held modifiers apply to later keyboard and mouse input in the same scene. Holding a key does not repeat automatically; call again to repeat. Caps Lock toggles only once until released and pressed again. (p/key-press! window :shift) (p/mouse-click! window [50 50] :primary) (p/key-release! window :shift)
(key-release! key)(key-release! el key)Release a virtual key; return the focus owner at the release.
el is a Window, Scene, or synthetic root; omission requires one open window. key is a javafx.scene.input.KeyCode or kebab-case keyword such as :shift. Release follows the scene's current focus owner, which may differ from the press target. Throws if there is no focus owner; desktop focus is not required.
Releasing a modifier stops applying it to later input. Other keys remain held. See key-press! for virtual keyboard rules; use key-tap! for a complete tap.
(p/key-release! window :shift)
Release a virtual key; return the focus owner at the release. el is a Window, Scene, or synthetic root; omission requires one open window. key is a javafx.scene.input.KeyCode or kebab-case keyword such as :shift. Release follows the scene's current focus owner, which may differ from the press target. Throws if there is no focus owner; desktop focus is not required. Releasing a modifier stops applying it to later input. Other keys remain held. See key-press! for virtual keyboard rules; use key-tap! for a complete tap. (p/key-release! window :shift)
(key-tap! key)(key-tap! el key)Press and release one key; return the focus owner at the release.
el is a Window, Scene, or synthetic root; omission requires one open window. key is a javafx.scene.input.KeyCode or kebab-case keyword, e.g. :a, :enter, :tab, :escape, :digit1, :space. Uses a virtual US layout: printable keys type text, Shift/Caps Lock affect case, and Control/Alt/Meta suppress typed text. See key-press! for full keyboard rules and key-chord! for combinations.
Input follows the scene's current focus owner, which can change after Tab. Throws if no focus owner exists; desktop focus is not required.
(p/key-tap! :enter) (p/key-tap! window :a)
Press and release one key; return the focus owner at the release. el is a Window, Scene, or synthetic root; omission requires one open window. key is a javafx.scene.input.KeyCode or kebab-case keyword, e.g. :a, :enter, :tab, :escape, :digit1, :space. Uses a virtual US layout: printable keys type text, Shift/Caps Lock affect case, and Control/Alt/Meta suppress typed text. See key-press! for full keyboard rules and key-chord! for combinations. Input follows the scene's current focus owner, which can change after Tab. Throws if no focus owner exists; desktop focus is not required. (p/key-tap! :enter) (p/key-tap! window :a)
(mouse-click! position button)(mouse-click! el position button)Press and release a mouse button at one position; return the release target or nil.
el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector [x y] in scene logical pixels from the content area's top-left, excluding window decorations. Use point to locate a node. button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton.
Clicks at the given position, with held keyboard modifiers applied.
(p/mouse-click! [50 50] :primary) (p/mouse-click! window (p/point node 0.5 0.5) :primary)
Press and release a mouse button at one position; return the release target or nil. el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector [x y] in scene logical pixels from the content area's top-left, excluding window decorations. Use point to locate a node. button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton. Clicks at the given position, with held keyboard modifiers applied. (p/mouse-click! [50 50] :primary) (p/mouse-click! window (p/point node 0.5 0.5) :primary)
(mouse-move! position)(mouse-move! el position)Move the virtual mouse to position [x y]; return the target or nil.
el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. Use point to obtain coordinates from a node.
Holding a mouse button drags the original press target. Held keyboard modifiers apply. Input in one scene does not affect another.
Movement is instantaneous and does not move the desktop pointer. Call repeatedly for intermediate positions. Outside the scene, the target can be nil; dragging continues to target the original press target.
(p/mouse-press! window [50 50] :primary) (p/mouse-move! window [150 100]) (p/mouse-release! window [150 100] :primary)
Move the virtual mouse to position [x y]; return the target or nil. el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. Use point to obtain coordinates from a node. Holding a mouse button drags the original press target. Held keyboard modifiers apply. Input in one scene does not affect another. Movement is instantaneous and does not move the desktop pointer. Call repeatedly for intermediate positions. Outside the scene, the target can be nil; dragging continues to target the original press target. (p/mouse-press! window [50 50] :primary) (p/mouse-move! window [150 100]) (p/mouse-release! window [150 100] :primary)
(mouse-press! position button)(mouse-press! el position button)Press a mouse button at position [x y]; return the event target or nil.
el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels, measured from the content area's top-left (excluding window decorations). button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton.
Presses at the given position, with held keyboard modifiers applied. Buttons stay held across calls, including mouse-move!, until released. Pair with mouse-release!, or use mouse-click! for a complete click. point converts a relative position within a node to scene coordinates.
(p/mouse-press! window (p/point node 0.5 0.5) :primary)
Press a mouse button at position [x y]; return the event target or nil. el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels, measured from the content area's top-left (excluding window decorations). button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton. Presses at the given position, with held keyboard modifiers applied. Buttons stay held across calls, including mouse-move!, until released. Pair with mouse-release!, or use mouse-click! for a complete click. point converts a relative position within a node to scene coordinates. (p/mouse-press! window (p/point node 0.5 0.5) :primary)
(mouse-release! position button)(mouse-release! el position button)Release a mouse button at position [x y]; return the event target or nil.
el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton. Use point to obtain coordinates from a node.
Release goes to the original press target, even at a different position. Other buttons remain held. Use mouse-click! for a press/release pair at one position.
(p/mouse-release! window [50 50] :primary)
Release a mouse button at position [x y]; return the event target or nil. el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. button is :primary, :middle, :secondary, or a javafx.scene.input.MouseButton. Use point to obtain coordinates from a node. Release goes to the original press target, even at a different position. Other buttons remain held. Use mouse-click! for a press/release pair at one position. (p/mouse-release! window [50 50] :primary)
(one & args)Return the single matching live element; throw on zero or multiple matches.
Optional el is a Node, Scene, Window, or synthetic root; omission searches all open windows. Selectors search descendants. Accepts the same selectors as all, including classes, #id/.class strings, property maps, and predicates. See all for chaining and direct-child syntax. Throws IllegalStateException unless exactly one element matches; use all to inspect ambiguous matches.
(p/one javafx.stage.Window) (p/one window "#name")
Return the single matching live element; throw on zero or multiple matches. Optional el is a Node, Scene, Window, or synthetic root; omission searches all open windows. Selectors search descendants. Accepts the same selectors as all, including classes, #id/.class strings, property maps, and predicates. See all for chaining and direct-child syntax. Throws IllegalStateException unless exactly one element matches; use all to inspect ambiguous matches. (p/one javafx.stage.Window) (p/one window "#name")
(point node x y)Return scene coordinates [x y] for a relative position within a node.
x and y must be numbers from 0 to 1 along the node's local layout bounds: 0,0 is top-left; 0.5,0.5 is center; 1,1 is bottom-right. The Node must belong to a Scene. Converts through ancestor transforms and enclosing SubScenes into the outer scene's coordinates, suitable for mouse input.
Reads current geometry on the JavaFX thread. The result is a snapshot; layout changes, clipping, or overlapping nodes can affect what gets clicked. Exact edges may not be pickable; use e.g. 0.95 to aim just inside an edge.
(p/point node 0.5 0.5) (p/mouse-click! window (p/point node 0.25 0.5) :primary)
Return scene coordinates [x y] for a relative position within a node. x and y must be numbers from 0 to 1 along the node's local layout bounds: 0,0 is top-left; 0.5,0.5 is center; 1,1 is bottom-right. The Node must belong to a Scene. Converts through ancestor transforms and enclosing SubScenes into the outer scene's coordinates, suitable for mouse input. Reads current geometry on the JavaFX thread. The result is a snapshot; layout changes, clipping, or overlapping nodes can affect what gets clicked. Exact edges may not be pickable; use e.g. 0.95 to aim just inside an edge. (p/point node 0.5 0.5) (p/mouse-click! window (p/point node 0.25 0.5) :primary)
(props el & {:keys [only]})Return a map of supported property values for el (a JavaFX element).
With no :only, discover all supported keys. :only selects keys to read; unsupported keys are omitted, while supported keys with nil values remain. Keys are kebab-case names from JavaFX property accessors and observable-list getters, e.g. :text, :id, :style-class. Values can include live JavaFX objects.
(p/props node) (p/props node :only [:id :text :visible])
Return a map of supported property values for el (a JavaFX element). With no :only, discover all supported keys. :only selects keys to read; unsupported keys are omitted, while supported keys with nil values remain. Keys are kebab-case names from JavaFX property accessors and observable-list getters, e.g. :text, :id, :style-class. Values can include live JavaFX objects. (p/props node) (p/props node :only [:id :text :visible])
(screenshot!)(screenshot! el)Save a screenshot to a temporary PNG; return its absolute path as a string.
el is a Node, Scene, Window, or synthetic root. Omitting it requires exactly one open window. A window captures its scene content, excluding decorations and separate popup windows. A node captures itself and its children, without surrounding content or overlapping siblings, on a transparent background.
(p/screenshot!) (p/screenshot! window) (p/screenshot! (p/one window "#chart"))
Save a screenshot to a temporary PNG; return its absolute path as a string. el is a Node, Scene, Window, or synthetic root. Omitting it requires exactly one open window. A window captures its scene content, excluding decorations and separate popup windows. A node captures itself and its children, without surrounding content or overlapping siblings, on a transparent background. (p/screenshot!) (p/screenshot! window) (p/screenshot! (p/one window "#chart"))
(scroll! position dx dy)(scroll! el position dx dy)Scroll at position [x y] by dx and dy logical pixels; return the target or nil.
el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. Use point to obtain coordinates from a node.
dx and dy are finite numbers; fractions are allowed. Negative dx scrolls right, negative dy scrolls down; positive values reverse those directions. Held keyboard modifiers apply. The control determines the actual movement and stops at its scroll limits. Scrolling is immediate, without momentum, and does not move the desktop pointer.
(p/scroll! window (p/point list-view 0.5 0.5) 0 -100) (p/scroll! [150 150] -100 0)
Scroll at position [x y] by dx and dy logical pixels; return the target or nil. el is a Window, Scene, or synthetic root; omission requires one open window. The scene must be in a showing window; desktop focus is not required. position is a vector of two finite numbers in scene logical pixels from the content area's top-left. Use point to obtain coordinates from a node. dx and dy are finite numbers; fractions are allowed. Negative dx scrolls right, negative dy scrolls down; positive values reverse those directions. Held keyboard modifiers apply. The control determines the actual movement and stops at its scroll limits. Scrolling is immediate, without momentum, and does not move the desktop pointer. (p/scroll! window (p/point list-view 0.5 0.5) 0 -100) (p/scroll! [150 150] -100 0)
(tree & args)Return a nested map describing el and its children.
el may be a Node, Scene, Window, or synthetic root. Omit it to inspect all open windows under that root. Each entry has :el (the live object) and a vector of :children. :props adds a property map; see props for supported keys. :depth limits child traversal: 0 omits :children, 1 includes immediate children, and omission traverses the full subtree.
Traversal follows windows to scenes to scene roots, then node children; SubScenes contribute their roots. Start with a small depth to limit output.
(p/tree :depth 2 :props [:title :id]) (p/tree window :depth 3 :props [:id :text]) ;; entry shape: {:el node :props {:id "name"} :children [...]}
Return a nested map describing el and its children.
el may be a Node, Scene, Window, or synthetic root. Omit it to inspect all
open windows under that root. Each entry has :el (the live object) and a
vector of :children. :props adds a property map; see props for supported keys.
:depth limits child traversal: 0 omits :children, 1 includes immediate
children, and omission traverses the full subtree.
Traversal follows windows to scenes to scene roots, then node children;
SubScenes contribute their roots. Start with a small depth to limit output.
(p/tree :depth 2 :props [:title :id])
(p/tree window :depth 3 :props [:id :text])
;; entry shape: {:el node :props {:id "name"} :children [...]}cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |