java - What is right way to work with tableview? -
for time have been trying tableview work kind of spreadsheet updated background thread , when cell updated, few seconds higlights ( changes style ) , goes original style. know, can't store , set styles directly in table cell , need kind of backing class, hold data. tableview "reusing" of cells (using same cells different data) acts weird. when cells fits on screen works flawlessly me, once place around 100 cells , becomes scrollable starts being buggy, styles ( or setted graphic) disappears , after scrolling appears, if disable top cells of view, other cells after scrolling disabled , on. there right way this?
what need
background data thread ---updates--> tableview thread --after few seconds removes style--> tableview
as have now, have model class holds data, style , reference table cell should ( disabled ordering, should ok ) , background thread updates data in model class, , model class changes style on referenced cell , register in "style remover" thread, after while removes style.
i think posting actual code won't useful, because once i've discovered cells being reused code has become complicated , little bit unreadable want redo right way.
peformance not important me, there wont more 100 cells, highlighting , having buttons in tableview must work flawlessly.
this how app looks - idea of need.
edit: here link another question related this.
the collaborators:
- on data side, (view) model has recentlychanged property, that's updated whenever value changed
- on view side, custom cell listens recentlychanged property , updates style appropriate
the tricky part clean cell state when re-used or not-used: method that's (hopefully!) called cell.updateindex(int newindex)
, that's place un-/register listener.
below runnable (though crude ;) example
import java.util.logging.logger; import java.util.stream.collectors; import java.util.stream.stream; import de.swingempire.fx.util.fxutils; import javafx.animation.keyframe; import javafx.animation.timeline; import javafx.application.application; import javafx.beans.property.readonlybooleanproperty; import javafx.beans.property.readonlybooleanwrapper; import javafx.beans.property.simplestringproperty; import javafx.beans.property.stringproperty; import javafx.beans.value.changelistener; import javafx.collections.fxcollections; import javafx.collections.observablelist; import javafx.scene.parent; import javafx.scene.scene; import javafx.scene.control.button; import javafx.scene.control.tablecell; import javafx.scene.control.tablecolumn; import javafx.scene.control.tableview; import javafx.scene.layout.borderpane; import javafx.scene.layout.hbox; import javafx.stage.stage; import javafx.util.duration; public class tablecorerecentlychanged extends application { public static class recentchanged extends tablecell<dummy, string> { private changelistener<boolean> recentlistener = (src, ov, nv) -> updaterecentstyle(nv); private dummy lastdummy; /* * see effect. */ protected void updaterecentstyle(boolean highlight) { if (highlight) { setstyle("-fx-background-color: #99ff99"); } else { setstyle("-fx-background-color: #009900"); } } @override public void updateindex(int index) { if (lastdummy != null) { lastdummy.recentlychangedproperty().removelistener(recentlistener); lastdummy = null; } updaterecentstyle(false); super.updateindex(index); if (gettablerow() != null && gettablerow().getitem() != null) { lastdummy = gettablerow().getitem(); updaterecentstyle(lastdummy.recentlychangedproperty().get()); lastdummy.recentlychangedproperty().addlistener(recentlistener); } } @override protected void updateitem(string item, boolean empty) { if (item == getitem()) return; super.updateitem(item, empty); if (item == null) { super.settext(null); super.setgraphic(null); } else { super.settext(item); super.setgraphic(null); } } } private parent getcontent() { tableview<dummy> table = new tableview<>(createdata(50)); table.seteditable(true); tablecolumn<dummy, string> column = new tablecolumn<>("value"); column.setcellvaluefactory(c -> c.getvalue().valueproperty()); column.setcellfactory(e -> new recentchanged()); column.setminwidth(200); table.getcolumns().addall(column); int editindex = 20; button changevalue = new button("edit"); changevalue.setonaction(e -> { dummy dummy = table.getitems().get(editindex); dummy.setvalue(dummy.getvalue()+"x"); }); hbox buttons = new hbox(10, changevalue); borderpane content = new borderpane(table); content.setbottom(buttons); return content; } private observablelist<dummy> createdata(int size) { return fxcollections.observablearraylist( stream.generate(dummy::new) .limit(size) .collect(collectors.tolist())); } private static class dummy { private static int count; readonlybooleanwrapper recentlychanged = new readonlybooleanwrapper() { timeline recenttimer; @override protected void invalidated() { if (get()) { if (recenttimer == null) { recenttimer = new timeline(new keyframe( duration.millis(2500), ae -> set(false))); } recenttimer.playfromstart(); } else { if (recenttimer != null) recenttimer.stop(); } } }; stringproperty value = new simplestringproperty(this, "value", "initial " + count++) { @override protected void invalidated() { recentlychanged.set(true); } }; public stringproperty valueproperty() {return value;} public string getvalue() {return valueproperty().get(); } public void setvalue(string text) {valueproperty().set(text); } public readonlybooleanproperty recentlychangedproperty() { return recentlychanged.getreadonlyproperty(); } public string tostring() {return "[dummy: " + getvalue() + "]";} } @override public void start(stage primarystage) throws exception { primarystage.setscene(new scene(getcontent())); // primarystage.settitle(fxutils.version()); primarystage.show(); } public static void main(string[] args) { launch(args); } @suppresswarnings("unused") private static final logger log = logger .getlogger(tablecorerecentlychanged.class.getname()); }
Comments
Post a Comment