JavaFX Table View CellValueFactory - java

I've ran into a weird problem which I can't seem to fix. I'm making a table view which one column has a checkbox inside of it.
Although I'm trying to add a change listener to the CheckBoxTableCell but not having any luck.
If I do this:
final CheckBoxTableCell<Plugin, Boolean> ctCell = new CheckBoxTableCell<>();
enabled.setCellFactory(p -> ctCell);
The checkbox's do not show up at all on the tableview.
But if I do this:
enabled.setCellFactory(p -> new CheckBoxTableCell<>());
The checkboxes show up fine? Why does the second one show the checkboxes but the first one doesn't? Please help!

In the first case you create an object and pass it multiple times. As per JavaFX scene graph documentation a node can only be attached to a single parent and a parent cannot have duplicate children.
In the second case you create a new object every time to populate the cells. This is what should be done, as the method expects a factory, in other words an object that produces a new object every call.

Related

How to get Values from the JFX Table

I need to get all values from JFX Table View. Tell me to way for that. it's very important to me. below has that table.
If you want to get all items in the TableView you can use the getItems method. Otherwise if you want only the selected data, you can use a SelectionModel to get the selected item.

Dynamic columns for JTreeTable

I am building a JTreeTable. I found some starter code and have come pretty far. In the end my goal is to be able to have different data at different levels like a hierarchical list.
Currently, I have it working with data at different levels. However, I am running up against a wall when it comes to changing the columns as a next goal. From where I currently stand I have 3 more milestones:
Show different set of columns for different levels
Ability to adjust column widths for different levels
Ensure the JTree part of the table always stays to left
I am getting close to closing out this task but again stuck at the first of these 3.
Since creating a JTreeTable is complex, the minimum example leverages several class listed below in the image:
I am happy to post the code to any of those classes but I also did not want clog the question with useless code. First let me show the functionality I want.
The first image is when the top level is selected and the second image is when the second level is selected. Notice how the columns are different. That is what I want to happen in my application.
Top level selected:
Second level selected:
So one way I tried to solve this problem, is when the list selection is changed inside this section of code:
ListSelectionListener listener = (ListSelectionEvent e) -> {
TreeTableModelAdapter adapter = (TreeTableModelAdapter) JTreeTable.this.getModel();
//Need to see why this breaks.
JTreeTable.this.getTableHeader().setColumnModel(adapter.getColumnModel());
};
this.getSelectionModel().addListSelectionListener(listener);
This code is in the initialization of the JTreeTable. I have tried setting the column model on both the TableHeader and the table as well. Below is what happens then when I select a row:
The columns just disappear on me. The creation of the column model is happening in the TreeTableModelAdapter class with the following method:
public TableColumnModel getColumnModel(){
DefaultTableColumnModel model = new DefaultTableColumnModel();
for(int i=0;i<getColumnCount();i++){
TableColumn column = new TableColumn();
column.setIdentifier(getColumnName(i));
model.addColumn(column);
}
return model;
}
Any direction would be very helpful. Again happy to post any code you think could be helpful to answer the question. Just put a comment in and I will add it right away.
I will add the milestones as I find them in case this helps others, but for now this question is answered.
Milestone 1
I was actually able to solve the first milestone. The key is to trigger the creation of the columns of the column model, not to create a new column model. Below is the code for when the row selection is changed:
//Change columns depending on row
ListSelectionListener listener = (ListSelectionEvent e) -> {
createDefaultColumnsFromModel();
};
this.getSelectionModel().addListSelectionListener(listener);
This code creates the columns based on the row selected in the JTree part of the JTreeTable. The TreeTableModelAdapter implements the getColumnCount() and getColumnName() methods by also passing the selected row in the JTree to the JTreeTableModel so that the columns and their names are dynamically retrieved based on a particular node in the JTree. The key for this for me was trigger those to be called again to update the JTreeTable.
Milestone 2
Adjusting column widths based on the data level proved to be much more difficult than I had originally anticipated. In order to retain the cells state when the column model changed I had to disconnect the painting of the cells from it. This is a hairy process because this is done inside BasicTableUI and the method that gets the rectangle of the cell is private. So I had to subclass it, overload the paint() method and create my own methods that get called inside the paint method. There was a lot of copy pasting so that I could call normally private methods. I just renamed them and referenced these methods instead. The way the ui class was designed did not make it very flexible. Below is 2 images where I am selecting different levels and the columns are obviously different widths at different levels.
Milestone 3
I was able to make this work by keeping track of the view in the model. This seems very dirty to me as the model should separated from the view. Since the tree column's class is unique, I just returned the right class if that column was the first in the view.
The one problem I have with this technique is that I get unexpected behavior where the value returned is not consistent. I attempted to resolve this by overriding JTree.covertValueToText(). Since a JTree only expects 1 value and depending on the sequence of columns in the view this value could change. So in overriding this method I check the stored index for the JTree column's value. Again this causes the unexpected behavior. I will update the post if I find the fix.

Populate list dynamically in Codename one

I had some issues with a List concept in Codename one. I need a list of items populate dynamically at run time, but I don't know how doing it, so anyone helps me regarding this issue?
Depending on how your list is constructed... E.g. when you have a form with a container, which includes your list as labels.
Container c = new Container(BoxLayout.y());
//adding strings as labels
c.add("String1").add("String2");
Then you can later on add a String to this container
c.add("new String");
But the form won't update itself. So you'd have to
form.revalidate() OR form.animateLayout(150)
to be able to show the changes on the screen.

How to load a part of composite keeping others static?

I have a form in SWT where I have five different composites based on one parent composite.Each of the composite contains different widgets like a single textbox / a combo box / a combination of text and combo etc.
Now the problem is when I click on the button I want to change my third composite to carry a different widget keeping others static.Now I can't reload from the beginning as I want current values of the other widgets to be displayed.How can I fetch only that composite,dispose it and create a new widget in place of that.
Creating and hiding the widget is difficult to consider as it is dynamic to at what place we want to redraw.
Here is the snippet.
formComposite=new Composite(parentComposite,SWT.BORDER_SOLID);
formLayout=new GridLayout(5,false);
fromComposite.setLayout(formLayout)
item.create(formComposite) //Here item is the widget (combo/textbox/combination text/combo)
formComposite1=new Composite(parentComposite,SWT.BORDER_SOLID);
formLayout1=new GridLayout(5,false);
fromComposite1.setLayout(formLayout)
item1.create(formComposite1))
formComposite2=new Composite(parentComposite,SWT.BORDER_SOLID);
formLayout2=new GridLayout(5,false);
fromComposite2.setLayout(formLayout)
item2.create(formComposite2))
formComposite3=new Composite(parentComposite,SWT.BORDER_SOLID);
formLayout3=new GridLayout(5,false);
fromComposite3.setLayout(formLayout)
item3.create(formComposite3))
formComposite4=new Composite(parentComposite,SWT.BORDER_SOLID);
formLayout4=new GridLayout(5,false);
fromComposite4.setLayout(formLayout)
item4.create(formComposite4))
Now how can I replace item3 with a different item to be created keeping others static in their place?
Assuming you only have one child for each Composite you can just dispose of the existing control and add the new one and then redo the layout.
item.dispose();
item = new Combo(fromComposite, ... style);
formComposite.layout(true);
You may also have to call layout on the parentComposite.
you could do this by using Control.moveAbove() and Control.moveBelow() methods
// create item3replacement
item3replacement.moveAbove(item3);
item3.dispose();
// call layout on parent when all is done
otherwise you will need to write your own Layout to do so.
as you are using GridLayout this will be your starting point.
you need to add a value for an position to GridData and process this in the GridLayout

Select a row in TableViewer

I have a TableViewer in my application that has the following features:
It gets data from a web service, and upon selecting a row, buttons get enabled and you can make operations (all these operations are calling the webservice, so the table stays in sync with the database).
When I add a new line, I submit an "add" command to the web service, and refresh the table. Now I have a new line, and I know which line is the new one.
Now I want to select the new line by default, and I tried many commands like tableViewer.getTable().select(index); and as it is now:
public void selectAdded(int id) {
tableViewer.getTable().setSelection(id);
}
This picture shows what is the problem:
The upper one shows as it works now with this code. The row below shows how it looks when I click a row. The problem is, the buttons don't get enabled, and I have two read-only text fields that remains blank instead of showing the information I need. But when I click, everything works normally.
What should I do to achive that selectAdded(int id) acts like a click? The solution should be multi-platform (Mac/Windows), but at least on Mac.
Don't use the Table selection methods which using TableViewer. Instead use
ISelection selection = new StructuredSelection(model object);
tableViewer.setSelection(selection);
'model object' is the model object for the row you want to select (as returned by your content provider).

Categories