I intent to use a TableModelListener to react on user entries of a JTable. I would like to know the column of the edited cell. Unfortunately, the method getColumn() returns -1 instead of the edited column number. Any idea why?
public class TableEventListener implements TableModelListener {
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE ) {
System.out.println(e.getColumn()); //prints -1
}
}
}
As noted in the TableModelEvent API for getColumn(), "If the return value is ALL_COLUMNS; it means every column in the specified rows changed." Note that ALL_COLUMNS has the value -1.
Related
Starting Point
I would like to implement a TableView in which each TableRow item will be checked for a certain boolean value. If this value holds true, then this row will be disabled for selection.
For instance I have a TableView with 3 TableRows (each holds a Person object). Now I would like the TableView to make those rows not-selectable whose Person object property is older than 18 years old.
Assume 2nd row fullfills the above condition and is therefore rendered not-selectable. So if my cursor currently is focused on the 1st row and I press the arrow down key, the TableView would skip any not-selectable rows (here: 2nd row) and select the next available selectable row (here: 3rd row)
My Approach
tblLineitems.setRowFactory(new Callback<TableView<Lineitem>, TableRow<Lineitem>>() {
public TableRow<Lineitem> call(TableView<Lineitem> tableview) {
return new TableRow<Lineitem>() {
#Override
protected void updateItem(Lineitem item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
} else {
itemProperty().addListener((ObservableValue<? extends Lineitem> observable, Lineitem oldValue, Lineitem newValue) -> {
if (newValue.isOlderThan18()) {
setDisable(true);
} else {
setDisable(false);
}
});
}
}
};
}
});
My Issue
Although I managed to setDisable(true) the affected rows, yet I can still select/mark them with the arrow down and up keys.
I played around with implementing a custom selection model and a focus model but ended-up using a hack (works for my use case). In my situation, I have to skip at most one row at a time. Therefore, inside the ChangeListener of the selectedItemProperty I ended up using the following function.
If I encounter an item row I trigger a callback, otherwise I skip the category row.
private fun MyListView.skipCategoryRow(
previousSelectionIndex: Int,
currentSelectionIndex: Int
) {
when {
currentSelectionIndex > previousSelectionIndex -> selectionModel.selectNext()
currentSelectionIndex > 1 -> selectionModel.selectPrevious()
/* prevent moving the selection to index 0, which is always a category row */
else -> selectionModel.selectNext()
}
}
One of the rows in my table is a ComboBox. They have the choice between 'Yes', 'No', 'Both'
If they choose Both have to make some modifications to the data array that is building the table and refresh the table. It was suggested in a previous post to build my logic in the else statement for Both.
protected void setValue(Object element, Object value)
{
if((element instanceof AplotDatasetData) && (value instanceof Integer)) {
Integer choice = (Integer)value;
String option = ((AplotDatasetData)element).getMarkupValue();;
if(choice == 0) {
option = "No";
}
else if(choice == 1) {
option = "Yes";
}
else {
option = "Both";
abd.getIndexOfSelectedBoth(); <<<<<<<<<
}
((AplotDatasetData)element).setMarkupValue(option);
getViewer().update(element, null);
}
}
The code above is in class OptionEditingSupport.
The table is in class AplotBaseDailog.
So in the OptionEditingSupport class, I imported the AplotBaseDailog class and assigned it.
AplotBaseDialog abd;
Then I wrote a method in the AplotBaseDailog class to get the row index of the column they just changed to Both. I need the index value to get the data from the array.
public void getIndexOfSelectedBoth() {
int row = viewer.getTable().getSelectionIndex();
AplotDataModel.getInstance().rebuildDataArray(row);
updateTableViewer();
}
Then I am passing in the index of the row to a method in my dataModel class. It is in the dataModel class that has the data array.
I am guessing I am reinventing the wheel here. There has to be a better way to do this process. Right now with all my code in place, I am getting a Null Pointer Error at the line that calls AplotBaseDialog
else {
option = "Both";
abd.getIndexOfSelectedBoth(); <<<<----
}
Can you get the index in the OptionEditingSupport class?
So you want to find the index of the AplotDatasetData for which "both" was selected.
Your ModelProvider (APlotDataModel) contains a List with your data, right?
Each List implements the method indexOf(Object). So you can get the index of your current object by using this method.
AplotDatasetData selected = ...
int index = AplotDataModel.getInstance().getIndexOf(selected);
and within your model:
public int getIndexOf(APlotDatasetData object)
{
return LIST_HOLDING_YOUR_DATA.indexOf(object);
}
I have a problem to get value of checkbox from jtable in java, that is when i get value by this code "table.getvalue(0,1)" then i can not get the right value.
returns value from JTable contains JCheckBox represents Boolean value,
toString returns "true" / "false"
more in the JTable tutorial
As a concrete example, I got the expected result when I added the following line to the loop in the actionPerformed() method of this example:
System.out.println((table.getValueAt(i, CHECK_COL)));
JTable get cehckbox value when check box is checked:-
table.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
for(int i=0;i<table.getModel().getRowCount();i++)
{
if ((Boolean) table.getModel().getValueAt(i,0))
{
System.out.println(">\t"+table.getSelectedRow());
break;
}
}
}
});
I added EditTextCell(stringTestEditTextCell) to Column(testColumn).
EditTextCell editTextCell = new EditTextCell();
Column stringColumn = new Column(
editTextCell) {
#Override
public String getValue(Record object) {
return object.getValue();
}
};
All cells in testColumn are editable.
I want 1st cell of column such way that 1st cell of column should be Non-Editable.
Following class is answer to my question. I Solved it and works fine. But getting error when user clicking on 1st cell of column.
class CustomEditTextCell extends EditTextCell{
#Override
public void render(com.google.gwt.cell.client.Cell.Context context,
String value, SafeHtmlBuilder sb) {
// context.getColumn()==2 indicate Record ID column and context.getIndex()==0 indicate non editable cell in 1st empty row
if(context.getColumn()==2 && ( context.getIndex()==0 || context.getIndex()%10 == 0)){
sb.appendHtmlConstant("<div contentEditable='false' unselectable='true'></div>");
}else{
super.render(context, value, sb);
}
}
}
You might extend EditTextCell and override the edit()-Method so that it only edits when you have not set a boolean flag that you that you need to set for the first cell.
I use a JTable which has its own cell renderer and cell editor.
Say, this table contains 2 columns and x rows:
The first column contains a boolean value, its own cell rendering and cell editor (a radiobutton)
The second column contains a string value, its own cell renderer: it makes it bold when the first column of the current row is set to true (radiobutton checked)
All the values are correctly updated by the editor but the 2nd row does not become bold when the radio button is set to true...
I have to check a radio button from a different row to see the changes
Where can I fire thoses changes ?
Cheers and thanks for your help
RadiobuttonTableCellEditor.java
public class RadiobuttonTableCellEditor extends DefaultCellEditor
implements ItemListener {
JRadioButton rb = new JRadioButton();
public RadiobuttonTableCellEditor(JCheckBox pCheckBox) {
super(pCheckBox);
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (value == null)
return null;
rb.addItemListener(this);
rb.setSelected((Boolean)value);
return rb;
}
public void itemStateChanged(ItemEvent e) {
super.fireEditingStopped();
}
public Object getCellEditorValue() {
rb.removeItemListener(this);
return rb.isSelected();
}
}
In your table model whenever your value changes you have to fire appropriate event. If your model is inherited from AbstractTableModel you can use several fireXXX methods. My guess is you should call them from setValueAt method.
If you know exact column and row - you can call fireTableCellUpdated, otherwise you can you probably have to use fireTableChanged since you have to update different column.
And of course you renderer should properly render new value.
It doesn't seem to make any sense to extend DeafultCellEditor there. Implementing a listener interface like that is also not a great idea.
Renderers work best as a thin layer. If another cell should change, then that needs to be reflected in the table model which should fire a relevant update event.
I guess it could help people with a similar problem, make a true radiobutton unique in a row, you'll have to extend the DefaultTableModel to modify its behaviour especially the setValueAt method
Cheers
/**
* When <code>column</code> is the column that contains the Boolean (in fact the radio button):
* If aValue == false and that it had a previous value set to true we don't do anything
* If aValue == true and that it had a previous value set to false, we set all the other booleans to false and this one to true
*/
#Override
public void setValueAt(Object aValue, int row, int column) {
if (column == colonneBoutonradio)
{
if (((Boolean)aValue && !(Boolean)super.getValueAt(row, column)))
for (int i = 0; i < this.getRowCount(); i++)
// i==row permet de vérifier si la ligne courante est celle à modifier (et donc celle à mettre à true)
super.setValueAt(i==row, i, colonneBoutonradio);
}
else
super.setValueAt(aValue, row, column);
}