Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numeric text field with TextFormatter #114

Closed
goober99 opened this issue Jan 3, 2021 · 3 comments
Closed

Numeric text field with TextFormatter #114

goober99 opened this issue Jan 3, 2021 · 3 comments
Labels
question Not an actual issue, a question

Comments

@goober99
Copy link

goober99 commented Jan 3, 2021

I've got a text field I want to limit input to numbers. Following the TextFormatter example, I can add a :value-converter :number, but that only takes effect once the field loses focus. Ideally, the user wouldn't even be able to type letters and such into the field.

Here's a solution that shows how to do it with Java and JavaFX. In addition, I want to restrict input to a range (between 20 and 20,000). This is what I came up with to translate that to Clojure and Cljfx:

; Below lower limit allowed so users can backspace.
(defn valid-freq? [input]
  (and (number? input) (<= input 20000)))

(defn frequency-field [{:keys [frequency]}]
  {:fx/type :text-field
   :text-formatter {:fx/type :text-formatter
                    :value-converter :number
                    :filter #(let [input (.getControlNewText %)]
                      (if (or (= input "") (valid-freq? (read-string input)))
                        %
                        nil))
                    :value frequency
                    :on-value-changed #(swap! *state assoc :frequency %)}})

This works. You are only able to enter numbers into the text field. But whenever the field loses focus, I get the following error:

clojure.lang.ExceptionInfo: Replace forbidden {:old-value #object[bleep.core$frequency_field$fn__1819 0x11c45420 "bleep.core$frequency_field$fn__1819@11c45420"], :new-value #object[bleep.core$frequency_field$fn__1819 0x223c3d55 "bleep.core$frequency_field$fn__1819@223c3d55"]}
	at cljfx.mutator$fn__1052.invokeStatic(mutator.clj:109)
...

Since the program continues working and responding (it doesn't crash) and the text field has been successfully limited to entering numbers, I'm happy to ignore the message as just a warning, but the full message is quite long and spams my stdout, so I thought I'd check if I was doing something wrong and if there is something I can do to make the message go away.

Also, using Clojure's Java interop (.getControlNewText %) was the only way I could find to access the state of the TextFormatter. Is there a more idiomatic way to do this with Cljfx (such as a :get-control-new-text key or something)?

@vlaaad
Copy link
Contributor

vlaaad commented Jan 5, 2021

Hi! :filter is a constructor argument of TextFormatter that cannot be modified afterward, that's why it's forbidden to change it — there is no way to apply the change. frequency-field tries to change it because it uses an anonymous function for the filter value, so every call to frequency-field will create a new instance of a filter function. You can fix this by making it a top-level function:

(def text-filter #(let [input (.getControlNewText %)]
                      (if (or (= input "") (valid-freq? (read-string input)))
                        %
                        nil)))

(defn frequency-field [{:keys [frequency]}]
  {:fx/type :text-field
   :text-formatter {:fx/type :text-formatter
                    :value-converter :number
                    :filter text-filter
                    :value frequency
                    :on-value-changed #(swap! *state assoc :frequency %)}})

@vlaaad vlaaad closed this as completed Jan 5, 2021
@vlaaad vlaaad added the question Not an actual issue, a question label Jan 5, 2021
@vlaaad
Copy link
Contributor

vlaaad commented Jan 5, 2021

I think your solution is fine! BTW AFAIK, the value is applied on Enter in addition to losing focus.

@goober99
Copy link
Author

goober99 commented Jan 6, 2021

Moving the filter to a named function got rid of the error messages. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Not an actual issue, a question
Projects
None yet
Development

No branches or pull requests

2 participants