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

Scroll To Selected Item #150

Open
dsbw opened this issue Nov 24, 2021 · 4 comments
Open

Scroll To Selected Item #150

dsbw opened this issue Nov 24, 2021 · 4 comments
Labels
question Not an actual issue, a question

Comments

@dsbw
Copy link

dsbw commented Nov 24, 2021

Hi, vlaaad!

Example 27 shows how to change the currently selected item on tables, trees, listbox—which works great—but if you shrink the window down, you'll notice that while the item will be selected, the control will not scroll to it.

How would we get that effect?

(In my situation, I've got a data entry form that adds an item to a table, and when the item in the data entry form is saved, it's put into the table and selected...but I'd like it also always be visible.)

@vlaaad
Copy link
Contributor

vlaaad commented Dec 2, 2021

Hi @dsbw !

Sorry for late reply. Is new item always last? You can try adapting e.g. this solution, something like:

{:fx/type fx/ext-on-instance-lifecycle
 :on-created (fn [^TableView view] (-> view .getItems ...))
 :desc {:fx/type :table-view ...}}

@vlaaad vlaaad added the question Not an actual issue, a question label Dec 2, 2021
@dsbw
Copy link
Author

dsbw commented Dec 5, 2021

Thanks, vlaaad!

This code "works" in the sense that it is called and seems to be called on the right object with the right parameters:

   :on-created (fn [view] 
      (let [s (-> view .getItems .size)]                                     
            (.scrollTo view (dec s))))

But I'm not seeing any actual change in the tableview. I'm trying to create a minimal example.

Update: OK, no big challenge, this shows exactly what I'm seeing, minus the fact in actual practice I have a row selected, but I think that shouldn't affect scrollTo:

(ns ezclj.utils.cljfx-ish)

(require '[cljfx.api :as fx]
         '[clojure.core.cache :as cache])

(def ctx
  (atom (fx/create-context
          {:items      [:a :b :c :d :e :f :g :h :i :j :k :l :m :n :o :p :q :r :s :t :u :v :w :x :y :z]}
          cache/lru-cache-factory)))

(defn view [{:keys [fx/context]}]
  {:fx/type :stage
   :showing true
   :scene   {:fx/type :scene
             :root      {:fx/type    fx/ext-on-instance-lifecycle
                         :on-created (fn [view]
                                       (let [s (-> view .getItems .size)]
                                         (println "SCROLLING TO: " (dec s))
                                         (.scrollTo view (dec s))))
                         :desc       {:fx/type :table-view
                                      :columns [{:fx/type            :table-column
                                                 :cell-value-factory identity}]
                                      :items   (fx/sub-val context :items)}}}})

(def renderer
  (fx/create-renderer
    :middleware (comp fx/wrap-context-desc (fx/wrap-map-desc (fn [_] {:fx/type view})))
    :opts {:fx.opt/type->lifecycle   (some-fn fx/keyword->lifecycle fx/fn->lifecycle-with-context)}))

(fx/mount-renderer ctx renderer)

You'll see it says "SCROLLING TO 25" but it won't actually scroll there. Or it is scrolling there and something else is forcing it to the top? And it doesn't matter what value you put in for (.scrollTo view ###).

@vlaaad
Copy link
Contributor

vlaaad commented Dec 6, 2021

What your code does is scrolling to view as soon as table is created. It was not yet laid out in a scene graph, so it probably has some default bounds and scrolling probably wouldn't work. You probably want to wrap your let in fx/run-later, so it's executed when it was already shown.

Also, this is not exactly what you want, right? You want scrolling on adding items to the table, so you also need to add items listener, i.e. a Clojure equivalent of view.getItems().addListener(...) like (-> view .getItems (addListener (reify ...)))

@dsbw
Copy link
Author

dsbw commented Dec 7, 2021

The fx/run-later doesn't seem to change anything:

  :on-created (fn [view]
                                     (fx/run-later (let [s (-> view .getItems .size)]
                                                     (println "SCROLLING TO: " (dec s))
                                                     (.scrollTo view (dec s)))))

You want scrolling on adding items to the table, so you also need to add items listener, i.e. a Clojure equivalent of view.getItems().addListener(...) like (-> view .getItems (addListener (reify ...)))

In this particular case, I have a tabbed pane where, when one tab shows the list of items and the other tab allows entry of the items, and on saving of the item it switches back to the list, so I'm not watching LIVE per se. Not sure how much that matters.

I swapped out the on-created to use a listener:

                       :on-created (fn [view]
                                     (println "CREATING!")
                                     (let [ol (-> view .getItems)]
                                       (.addListener ol
                                                     (reify
                                                       ListChangeListener
                                                       (onChanged [this c]
                                                         (println "LISTENING!" c)
                                                         (.scrollTo view (.size ol)))))))

And then at the bottom, I added to items:

(Thread/sleep 1000)
(println "TICK")
(swap! ctx fx/swap-context update :items conj "XXX")

When I run it, I see:

Loading src/ezclj/utils/cljfx_ish.clj... CREATING!

TICK
Loaded
LISTENING! #object[javafx.collections.ListChangeBuilder$SingleChange 0x695b74cf { [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z] replaced by [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z, XXX] at 0 }]

Which is what I'd expect, though it still does not scroll.

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