listview - javafx Tableview cell index/editing bug with duplicated entries -
i've been messing around javafx bit. , came across cannot realy explain. trying create editable tableview string values. , worked, till started biger tests. before tested small lists, didn't exceed list's visible limit. though big test, list far more bigger show in window.
the problem give amount of cells @ begin of tableview collour, works perfectly, till start scrolling down. seems re-used cells aren't updated fast enough, since have been given wrong colour. when scrolling down, , updating more cells, patern of 'wrong coloured cells' changes well. interesting part is, these 'fails' consistent!
(btw, im checking cells index using this.getindex() after call this.setstyle() proper colour syntax.)
the second thing noticed, when start editing cell, though dont stop editing , scroll down. there multiple cells being edited @ same time. (also in consistent patern) , not visual glitch!, have debugged it, , seems editing property isn't updated enough either.
one last side note, update tablecells' graphics in cell#updateitem() method. (and editing part in cell#startedit() , cell#canceledit() well.)
my question is, bug? , if so, there workaround? please leave comment if have idea's/suggestions/solutions.
thanks in advance!
edit 01:
first need appoligize, since problem ocuring tableview, not listview. being said, made example class displays exactually problem tried describe. if there suggestions/solutions, please let me know!
package testpacket; import java.util.arrays; import javafx.application.application; import javafx.collections.fxcollections; import javafx.collections.observablelist; import javafx.scene.scene; import javafx.scene.control.tablecell; import javafx.scene.control.tablecolumn; import javafx.scene.control.tableview; import javafx.scene.layout.anchorpane; import javafx.stage.stage; public class tableviewtest extends application { private static observablelist<string> examplelist = fxcollections.observablearraylist(); private static string[] testarray = new string[50]; public static void main(string[] args) { launch(args); } @override public void start(stage primarystage) throws exception { // basic ui setup anchorpane parent = new anchorpane(); scene scene = new scene(parent); primarystage.setscene(scene); //fill backinglist data arrays.fill(testarray, 0, testarray.length, "test string"); examplelist.setall(arrays.aslist(testarray)); //create basic tableview tableview<string> listview = new tableview<string>(); tablecolumn<string, string> column = new tablecolumn<string, string>(); column.setcellfactory(e -> new tablecelltest<string, string>()); column.setcellvaluefactory(e -> new simplestringproperty(e.getvalue())); // set listviews' backing list listview.getitems().addall(examplelist); // listview.setitems(examplelist); doesnt rely on backing list, either way showing bug. listview.getcolumns().clear(); listview.getcolumns().add(column); parent.getchildren().add(listview); primarystage.show(); } public static class tablecelltest<s, t> extends tablecell<s, t> { @override protected void updateitem(t item, boolean empty) { super.updateitem(item, empty); // dipslays cells' value this.settext((string)this.getitem()); // checks cells index , set color. if(this.getindex() < 12) this.setstyle("-fx-background-color: rgba(253, 255, 150, 0.4);"); else this.setstyle(""); } } } edit 02:
@james_d
many answer, indeed duplicated items problem. somehow javafx checking whether content has changed or not. unfortunatly solution:
testarray[i] = new string("test string");
not work, quit unfortunate because system depends heavily on duplicated entries. trying make them unique impossible handle perfectly.
so hope there possibility overwrite 'is equal check' somehow. have been diging bit, , seems methods/fields private. changing kinda impossible do, unless recreate bunch of javafx classes.
so please if there still suggestion/solutions one, feel free post them!
onto next problem though, editing property isnt updated enough either. in onupdateitem() method check if current cell editing , keep updating cell stays in editing mode, if scroll down (and scrolling editing index out of window). made example can see yourself.
note when remove onupdateitem() part of editing system, cell exit edit mode after has been scrolled outside viewwindow.
package testpacket; import java.util.arrays; import javafx.application.application; import javafx.beans.property.simplestringproperty; import javafx.collections.fxcollections; import javafx.collections.observablelist; import javafx.event.eventhandler; import javafx.scene.scene; import javafx.scene.control.tablecell; import javafx.scene.control.tablecolumn; import javafx.scene.control.tableview; import javafx.scene.control.textfield; import javafx.scene.input.keycode; import javafx.scene.input.keyevent; import javafx.scene.layout.anchorpane; import javafx.stage.stage; public class tableviewtest extends application { private static observablelist<string> examplelist = fxcollections.observablearraylist(); private static string[] testarray = new string[50]; public static void main(string[] args) { launch(args); } @override public void start(stage primarystage) throws exception { // basic ui setup anchorpane parent = new anchorpane(); scene scene = new scene(parent); primarystage.setscene(scene); //fill backinglist data for(int = 0 ; < testarray.length; i++) testarray[i] = "test string" + i; // arrays.fill(testarray, 0, testarray.length, new string("test string")); examplelist.setall(arrays.aslist(testarray)); //create basic tableview tableview<string> listview = new tableview<string>(); tablecolumn<string, string> column = new tablecolumn<string, string>(); column.setcellfactory(e -> new tablecelltest<string, string>()); column.setcellvaluefactory(e -> new simplestringproperty(e.getvalue())); column.seteditable(true); // set listviews' backing list listview.getitems().addall(examplelist); listview.seteditable(true); // listview.setitems(examplelist); doesnt rely on backing list, either way showing bug. listview.getcolumns().clear(); listview.getcolumns().add(column); parent.getchildren().add(listview); primarystage.show(); } public static class tablecelltest<s, t> extends tablecell<s, t> { protected textfield textfield; @override public void startedit() { super.startedit(); if (!iseditable() || (this.gettableview() != null && !this.gettableview().iseditable()) || (this.gettablecolumn() != null && !this.gettablecolumn().iseditable())) return; if(this.textfield == null) this.createtextfield(); this.textfield.settext((string)this.getitem()); this.setgraphic(this.textfield); this.textfield.selectall(); this.settext(null); } @override public void canceledit() { super.canceledit(); if (!isediting()) return; this.settext((string)this.getitem()); this.setgraphic(null); } @override protected void updateitem(t item, boolean empty) { super.updateitem(item, empty); if(empty || item == null) { this.settext(null); this.setgraphic(null); } else { // tried option check whether cell represents correct item, though doesnt work if(this.isediting())// && this.gettableview().geteditingcell() != null && this.gettableview().geteditingcell().equals(this)) { if(this.textfield != null) this.textfield.settext((string)this.getitem()); this.settext(null); this.setgraphic(this.textfield); } else { this.settext((string)this.getitem()); this.setgraphic(null); } } } @suppresswarnings("unchecked") public void createtextfield() { this.textfield = new textfield(); this.textfield.setonkeyreleased((eventhandler<? super keyevent>)e -> { if(e.getcode() == keycode.enter) { this.setitem((t)this.textfield.gettext()); this.commitedit(this.getitem()); } else if(e.getcode() == keycode.escape) this.canceledit(); }); } } } edit 03:
unlike mentioned in class, there workaround one. note works 'single cell editing mode'! (as mode supported tableview) solution follows:
if(this.isediting() && this.gettableview().geteditingcell() != null && this.gettableview().geteditingcell().gettablecolumn().getcelldata(this.gettableview().geteditingcell().getrow()).equals(this.getitem())) { ... stuff } though unfortunatly doesn't solve index problem. thread still open suggestions/solutions.
the highlighting problem arises because have identical elements in table: i.e. have table.getitems().get(0)==table.getitems().get(1) etc. if change table initialization items not identical (but still equal):
// arrays.fill(testarray, 0, testarray.length, "test string"); (int = 0 ; < testarray.length; i++) testarray[i] = new string("test string"); then highlighting works expected.
to persist editing state during scrolling (including case editing cell scrolled out of view), need careful distinguish between cells , items. want persist item being edited: since cell may reused during scrolling means need way of keeping track of item being edited during scrolling; in updateitem(...) method need check , "go editing mode" if necessary. easiest way track item being edited using row index.
the following example shows way this:
import java.util.arrays; import javafx.application.application; import javafx.beans.property.simplestringproperty; import javafx.collections.fxcollections; import javafx.collections.observablelist; import javafx.scene.scene; import javafx.scene.control.contentdisplay; import javafx.scene.control.tablecell; import javafx.scene.control.tablecolumn; import javafx.scene.control.tableview; import javafx.scene.control.textfield; import javafx.scene.input.keycode; import javafx.scene.input.keyevent; import javafx.scene.layout.anchorpane; import javafx.stage.stage; import javafx.util.callback; public class tableviewtest extends application { public static void main(string[] args) { launch(args); } @override public void start(stage primarystage) throws exception { // basic ui setup anchorpane parent = new anchorpane(); scene scene = new scene(parent); primarystage.setscene(scene); //create basic tableview tableview<string> table = new tableview<string>(); table.seteditable(true); tablecolumn<string, string> column = new tablecolumn<string, string>(); column.setcellfactory(new cellfactory()); column.setcellvaluefactory(celldata -> new simplestringproperty(celldata.getvalue())); column.setoneditcommit(e -> { int row = e.gettableposition().getrow() ; table.getitems().set(row, e.getnewvalue()); }); (int = 0 ; < 50; i++) { table.getitems().add(new string("test")); } table.getcolumns().add(column); parent.getchildren().add(table); primarystage.show(); } public static class cellfactory implements callback<tablecolumn<string, string>, tablecell<string, string>> { private int editingindex = -1 ; @override public tablecell<string, string> call(tablecolumn<string, string> param) { return new tablecell<string, string>() { private textfield textfield = new textfield() ; { textfield.setonaction(e -> commitedit(textfield.gettext())); textfield.addeventfilter(keyevent.key_pressed, e -> { if (e.getcode() == keycode.escape) { canceledit(); } }); setgraphic(textfield); setcontentdisplay(contentdisplay.text_only); } @override protected void updateitem(string item, boolean empty) { super.updateitem(item, empty); if (getindex() != -1 && getindex() == editingindex) { setcontentdisplay(contentdisplay.graphic_only); } else { settext(empty ? null : item); setcontentdisplay(contentdisplay.text_only); } // checks cells index , set color. if(this.getindex() >= 0 && getindex() < 12) this.setstyle("-fx-background-color: rgba(253, 255, 150, 0.4);"); else this.setstyle(""); } @override public void startedit() { editingindex = getindex(); super.startedit(); textfield.settext(getitem()); setcontentdisplay(contentdisplay.graphic_only); } @override public void commitedit(string newvalue) { editingindex = -1 ; super.commitedit(newvalue); setcontentdisplay(contentdisplay.text_only); } @override public void canceledit() { settext(gettableview().getitems().get(editingindex)); editingindex = -1 ; super.canceledit(); setcontentdisplay(contentdisplay.text_only); } }; } } }
Comments
Post a Comment