cljfx

https://github.com/cljfx/cljfx
Ben Sless 2020-12-02T13:39:26.166100Z

Hi, I'm trying to get started with cljfx, tried both with lein and cli but I'm unable to load cljfx.api for some reason

(require '[cljfx.api :as fx])
Execution error (FileNotFoundException) at user/eval14091 (REPL:1).
Could not locate cljfx/api__init.class, cljfx/api.clj or cljfx/api.cljc on classpath.
These are the deps I tried with
{:deps
 {org.clojure/clojure {:mvn/version "1.10.1"}}
 {commons-io/commons-io {:mvn/version "2.8.0"}}
 {cljfx {:git/url "<https://github.com/cljfx/cljfx>" :sha "LATEST"}}
 :paths ["src"]}
Using java 11 on arm64 Weirdly enough, I am able to find and load other namespaces when using lein:
(require '[cljfx.fx :as fx])
works just fine Please advise?

vlaaad 2020-12-02T13:39:54.166400Z

:sha "LATEST" ?

Ben Sless 2020-12-02T13:40:18.166600Z

I also tried with a real sha

Ben Sless 2020-12-02T13:40:25.167Z

{cljfx {:git/url "<https://github.com/cljfx/cljfx>" :sha "955514a7968677d674ecc79126af428a9f21c91c"}}

vlaaad 2020-12-02T13:40:35.167300Z

there is something wrong with your deps.edn

Ben Sless 2020-12-02T13:40:45.167700Z

oh

vlaaad 2020-12-02T13:40:47.168Z

{commons-io/commons-io {:mvn/version "2.8.0"}} is a key

Ben Sless 2020-12-02T13:40:50.168200Z

I see it!

Ben Sless 2020-12-02T13:40:53.168400Z

damn

Ben Sless 2020-12-02T13:41:09.168600Z

still had the issue with lein, though

Ben Sless 2020-12-02T13:41:22.168800Z

with these deps:

:dependencies [[org.clojure/clojure "1.10.1"]
                 [commons-io/commons-io "2.8.0"]
                 [cljfx "1.7.10"]]

vlaaad 2020-12-02T13:41:50.169Z

is error the same?

Ben Sless 2020-12-02T13:43:14.169300Z

(require '[cljfx.api :as fx])
Syntax error compiling at (*cider-repl Projects/clj-dedupe-fs:localhost:36281(clj)*:1:21).
namespace 'cljfx.api' not found
yeah

vlaaad 2020-12-02T13:43:39.169600Z

what’s in *e?

Ben Sless 2020-12-02T13:44:05.170Z

#error {
 :cause "namespace 'cljfx.api' not found"
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Syntax error compiling at (*cider-repl Projects/clj-dedupe-fs:localhost:36281(clj)*:1:21)."
   :data #:clojure.error{:phase :compile-syntax-check, :line 1, :column 21, :source "*cider-repl Projects/clj-dedupe-fs:localhost:36281(clj)*"}
   :at [clojure.core$throw_if invokeStatic "core.clj" 5867]}
  {:type java.lang.Exception
   :message "namespace 'cljfx.api' not found"
   :at [clojure.core$apply invokeStatic "core.clj" 667]}]

vlaaad 2020-12-02T13:44:27.170400Z

is this all? no stacktrace?

Ben Sless 2020-12-02T13:44:48.170800Z

there is a trace, was wondering if you wanted it

Ben Sless 2020-12-02T13:44:51.171100Z

[[clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core$load_libs invokeStatic "core.clj" 5985]
  [clojure.core$load_libs doInvoke "core.clj" 5969]
  [clojure.lang.RestFn applyTo "RestFn.java" 137]
  [clojure.core$apply invokeStatic "core.clj" 667]
  [clojure.core$require invokeStatic "core.clj" 6007]
  [clojure.core$require doInvoke "core.clj" 6007]
  [clojure.lang.RestFn invoke "RestFn.java" 408]
  [clj_dedupe_fs.core$eval15884 invokeStatic "form-init3277701471284635884.clj" 1]
  [clj_dedupe_fs.core$eval15884 invoke "form-init3277701471284635884.clj" 1]
  [clojure.lang.Compiler eval "Compiler.java" 7177]
  [clojure.lang.Compiler eval "Compiler.java" 7132]
  [clojure.core$eval invokeStatic "core.clj" 3214]
  [clojure.core$eval invoke "core.clj" 3210]
  [nrepl.middleware.interruptible_eval$evaluate$fn__2542$fn__2543 invoke "interruptible_eval.clj" 87]
  [clojure.lang.AFn applyToHelper "AFn.java" 152]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.core$apply invokeStatic "core.clj" 665]
  [clojure.core$with_bindings_STAR_ invokeStatic "core.clj" 1973]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1973]
  [clojure.lang.RestFn invoke "RestFn.java" 425]
  [nrepl.middleware.interruptible_eval$evaluate$fn__2542 invoke "interruptible_eval.clj" 87]
  [clojure.main$repl$read_eval_print__9086$fn__9089 invoke "main.clj" 437]
  [clojure.main$repl$read_eval_print__9086 invoke "main.clj" 437]
  [clojure.main$repl$fn__9095 invoke "main.clj" 458]
  [clojure.main$repl invokeStatic "main.clj" 458]
  [clojure.main$repl doInvoke "main.clj" 368]
  [clojure.lang.RestFn applyTo "RestFn.java" 137]
  [clojure.core$apply invokeStatic "core.clj" 665]
  [clojure.core$apply invoke "core.clj" 660]
  [refactor_nrepl.ns.slam.hound.regrow$wrap_clojure_repl$fn__11776 doInvoke "regrow.clj" 20]
  [clojure.lang.RestFn invoke "RestFn.java" 1523]
  [nrepl.middleware.interruptible_eval$evaluate invokeStatic "interruptible_eval.clj" 84]
  [nrepl.middleware.interruptible_eval$evaluate invoke "interruptible_eval.clj" 56]
  [nrepl.middleware.interruptible_eval$interruptible_eval$fn__2573$fn__2577 invoke "interruptible_eval.clj" 152]
  [clojure.lang.AFn run "AFn.java" 22]
  [nrepl.middleware.session$session_exec$main_loop__2640$fn__2644 invoke "session.clj" 202]
  [nrepl.middleware.session$session_exec$main_loop__2640 invoke "session.clj" 201]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 834]]}

vlaaad 2020-12-03T08:19:42.176700Z

great question 😄

vlaaad 2020-12-03T08:21:13.176900Z

by default JavaFX pulls native libraries for the same platform the build tool is running on and skips others, so uberjar will work only on the platform the uberjar is built on

vlaaad 2020-12-03T08:22:08.177100Z

if you want to create cross-platform uberjar, you’ll need to specify all classifiers explicitly, e.g. like it’s done here https://github.com/defold/defold/blob/editor-dev/editor/project.clj#L81-L108

vlaaad 2020-12-03T08:22:48.177400Z

(note: for cljfx project you won’t need javafx-fxml and javafx-swing)

vlaaad 2020-12-03T08:23:55.177600Z

if you want to create cross-platform application, I’d recommend looking at https://github.com/cljfx/hn

vlaaad 2020-12-03T08:24:31.177900Z

it’s not too hard to build an installable app

Ben Sless 2020-12-03T09:08:44.178100Z

Thanks again 🙂 I find the documentation a bit obtuse so I have resorted to reading the README very slowly and carefully and working through the examples. Any recommendations on getting started or a development guide? I'm not familiar with JavaFX or UI development at all, and I think what I'm missing the most (maybe?) is discoverability. How do I know tables should have cells? How can I know what attributes are there? That kind of stuff.

vlaaad 2020-12-03T09:28:59.178300Z

I thought about making some sort of a repl helper that answers these questions, but time/priorities…

vlaaad 2020-12-03T09:30:10.178500Z

what I do is: - use javafx javadoc to see what options are available https://openjfx.io/javadoc/12/javafx.graphics/javafx/scene/Node.html in JavaFX - open cljfx.fx.* files to get a reminder of what are props

Ben Sless 2020-12-03T09:31:26.178700Z

alright, better than nothing, I'll give it a shot

vlaaad 2020-12-03T09:31:37.178900Z

for example, if I want to configure a table, I open cljfx/fx/table_view.clj to see its props and https://openjfx.io/javadoc/12/javafx.controls/javafx/scene/control/TableView.html to see its docs

🙏 1
Ben Sless 2020-12-03T09:33:06.179300Z

What do you think about qualifying each view's props with a ns? for example a table would map to fx.table/prop-name?

vlaaad 2020-12-03T09:56:45.179600Z

I thought about it at the start, but decided not to do it because you’ll have to deal with inheritance, e.g. some table props are coming from its superclass, so the use will be something like {:fx/type :fx.type/table :fx.table/items [] :fx.control/tooltip {...} :fx.node/style {...}}

vlaaad 2020-12-03T09:57:54.179800Z

maybe that was a mistake to not do it, what do you think? I didn’t like the idea of having to keep this class hierarchy in the code, but perhaps it’s “essential”?

Ben Sless 2020-12-03T11:52:30.180Z

It looks like in any case I'm forced to know and understand JavaFX and consult its documentation, so perhaps reflecting the class taxonomy might not be too harmful. It would also direct the user to the appropriate class they want to configure when referring to the documentation instead of jumping around. Another option / complement to this idea is using specs to describe the different views. Even adding a simple utility function which can be called on the :fx/type for user convenience will go a very long way, something like (api/props-for :table) which will give a list of keys or a map of key-type.

vlaaad 2020-12-03T11:53:45.180500Z

I experimented a bit with it

vlaaad 2020-12-03T11:55:42.180700Z

If I were to do it properly, I’d do it with spec, but time/priorities…

vlaaad 2020-12-03T11:58:23.180900Z

> It looks like in any case I’m forced to know and understand JavaFX that’s correct, there is no way around that, just like with react where you still have to know DOM. react/cljfx is an abstraction layer with better semantics

Ben Sless 2020-12-03T11:59:46.181100Z

That makes me lean more towards preferring namespace qualified keywords

Ben Sless 2020-12-03T12:00:36.181300Z

regarding spec, you can always open an issue and label it PRs welcome, maybe share it on twitter/clojurians

👍 1
vlaaad 2020-12-02T13:46:11.171500Z

Hmm, I assuming you call (require 'cljfx.api) in clj-dedupe-fs.core ns?

Ben Sless 2020-12-02T13:46:40.171700Z

(ns clj-dedupe-fs.core
  (:require
   [cljfx.api :as fx])
  (:import
   [javafx.stage FileChooser]
   [javafx.event ActionEvent]
   [javafx.scene Node]
   (<http://java.io|java.io> File)
   (<http://org.apache.commons.io|org.apache.commons.io> FileUtils)))

vlaaad 2020-12-02T13:47:12.171900Z

If you can require other nses such as cljfx.fx, it probably means there is some exception during the start of JavaFX runtime

vlaaad 2020-12-02T13:47:22.172100Z

I was hoping you could see it somehow

Ben Sless 2020-12-02T13:48:00.172300Z

Maybe I can see it if I clone cljfx and try there

vlaaad 2020-12-02T13:48:32.172500Z

can you try (import 'javafx.application.Platform) ?

vlaaad 2020-12-02T13:48:43.172700Z

and then (Platform/startup #(Platform/setImplicitExit false))

vlaaad 2020-12-02T13:48:51.172900Z

is there an exception at some point?

Ben Sless 2020-12-02T13:49:09.173100Z

let's see

Ben Sless 2020-12-02T13:50:21.173300Z

Import succeeded, startup failed with exception

Execution error (IllegalStateException) at com.sun.javafx.application.PlatformImpl/startup (PlatformImpl.java:182).
Toolkit already initialized

vlaaad 2020-12-02T13:51:21.173600Z

hmm

vlaaad 2020-12-02T13:51:31.173800Z

that looks okay

Ben Sless 2020-12-02T13:52:31.174Z

okay, cloned cljfx and tried just evaluating the api file

vlaaad 2020-12-02T13:52:33.174200Z

that means JavaFX works and you should be able to require cljfx.api

Ben Sless 2020-12-02T13:52:33.174400Z

and voila

Ben Sless 2020-12-02T13:52:51.174600Z

Loading library prism_es2 from resource failed: java.lang.UnsatisfiedLinkError: /home/bsless/.openjfx/cache/14/libprism_es2.so: /home/bsless/.openjfx/cache/14/libprism_es2.so: cannot open shared object file: No such file or directory (Possible cause: can't load AMD 64-bit .so on a AARCH64-bit platform)
java.lang.UnsatisfiedLinkError: /home/bsless/.openjfx/cache/14/libprism_es2.so: /home/bsless/.openjfx/cache/14/libprism_es2.so: cannot open shared object file: No such file or directory (Possible cause: can't load AMD 64-bit .so on a AARCH64-bit platform)

Ben Sless 2020-12-02T13:53:03.174800Z

It's because I'm on arm?

vlaaad 2020-12-02T13:53:49.175Z

I would say yes, there are javafx native libs for various platforms, and I don’t remember seeing arm among them…

Ben Sless 2020-12-02T13:54:51.175200Z

Well then, it's 1-0 for java vs. one janky arm laptop 🙂

vlaaad 2020-12-02T13:55:25.175700Z

I just googled it and there seems to be something for arm

vlaaad 2020-12-02T13:55:50.175900Z

you are on your own there I’m afraid :)

Ben Sless 2020-12-02T13:57:06.176100Z

It's okay, I'll work on it on another machine, thank you for helping 🙂

👍 1
Ben Sless 2020-12-02T13:57:57.176500Z

Also have a preemptive question: uberjars built with javafx work cross platform on windows, linux and mac or do I need to make sure some extra deps are included or have specific builds?