I use a HashMap to fill a JTable, which is more or less continuously updated:
public Map< Long, MyObject > tableData = new HashMap< Long, MyObject >();
Every time a new element is added to the map the table model is notified:
tableData.put(id, anObject);
AbstractTableModel atm = (AbstractTableModel)model;
atm.fireTableDataChanged();
In Addition I have a TableRowSorter which sorts the rows according to a specific criteria:
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
.
.
.
table.setRowSorter(sorter);
My goal is that the (vertical) scrollbar always jumps to the last added row, which can be somwhere in the mid
of the table because of the sorter probably using this:
table.scrollRectToVisible(table.getCellRect(row,0, true));
The problem is I do not know the index of the row :) Where can I hook in to get this index?
Scrolling to a newly inserted row in a potentially sorted table involves
listening to changes in the table model
converting the rowIndex of the event (it is in model coordiates) to view coordinates
scrolling to the view position
In code:
final JTable table = new JTable();
TableModelListener l = new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if (TableUtilities.isInsert(e)) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
int viewRow = table.convertRowIndexToView(e.getFirstRow());
table.scrollRectToVisible(table.getCellRect(viewRow, 0, true));
}
});
}
}
};
table.getModel().addTableModelListener(l);
Two important aspects:
your model implemenation must fire the correct event, that is a insert, not a dataChanged
invoking both index conversion and scrolling guarantees that the table (which is listening to the model as well) has updated all internal state according to the model change.
Related
I have two JTables which share a TableModel.
This is so that I can set them up in a scroll pane such that one of them has a few columns showing on the left and does not scroll sideways, visually 'freezing' those columns, and the other contains the rest of the columns.
They are always sorted the same so that the rows match up. This is done using a RowSorter listener, shown below. (frozenTable and tableView are the names of my JTables).
RowSorterListener rowSorterListener = new RowSorterListener() {
#Override
public void sorterChanged(RowSorterEvent e) {
if (RowSorterEvent.Type.SORT_ORDER_CHANGED == e.getType()) {
RowSorter source = e.getSource();
if (source == tableView.getRowSorter()) {
frozenTable.getRowSorter().removeRowSorterListener(this);
frozenTable.getRowSorter().setSortKeys(source.getSortKeys());
frozenTable.getRowSorter().addRowSorterListener(this);
} else {
tableView.getRowSorter().removeRowSorterListener(this);
tableView.getRowSorter().setSortKeys(source.getSortKeys());
tableView.getRowSorter().addRowSorterListener(this);
}
}
}
};
At another point in my code, I want to be able to get the TableColumn objects that are currently being sorted on. Before I added the frozentable, I was able to do this with the following code:
List<? extends SortKey> sortKeys = tableView.getRowSorter().getSortKeys();
for(SortKey key : sortKeys){
TableColumn column = tableView.getColumnModel().getColumn(key.getColumn());
// other stuff in the loop
}
It seems as though a SortKey only has two things in it, a column index and a SortOrder. This raises two questions:
How is my RowSorterListener even managing to sort the tables based on columns from one or the other table? If all I'm passing when I say 'setSortKeys' is 'sort by column 3' and column 3 is different for each JTable, then how is this working in the first place? Because it does work. If I have a Name column in the frozenTable and an Age column in the tableView and I sort by Age, it does sort both JTables by the Age column.
How do I get the TableColumn object associated with a SortKey?
Check out the Fixed Column Table which is a reusable class that allows you to share a model between two tables
The code to create the fixed column table is:
JTable table = new JTable(...);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JScrollPane scrollPane= new JScrollPane( table );
FixedColumnTable fct = new FixedColumnTable(2, scrollPane);
JTable fixed = fct.getFixedTable();
I don't think you need the sorter listener.
You should just be able to share the RowSorter using code something like:
table.setAutoCreateRowSorter(true);
fixed.setRowSorter(table.getRowSorter());
table.setUpdateSelectionOnSort(true);
fixed.setUpdateSelectionOnSort(false);
Is there a way I can delete the highlighted selected columns in this jtable using the remove button? I know there's a way for rows but I'm not sure how to do this for selected columns.
private void RemoveColBActionPerformed(java.awt.event.ActionEvent evt) {
// Removes the highlighted column
}
private void AddBActionPerformed(java.awt.event.ActionEvent evt) {
//Add Data
lMessage.setText("");
DefaultTableModel model = (DefaultTableModel) JtableData.getModel();
if (!ProdNameTF.getText().trim().equals("")) {
model.addRow(new Object[] {
ProdNameTF.getText(), CategoryCB.getSelectedItem().toString(), PriceTF.getText()
});
} else {
lMessage.setText("Message Left Blank");
}
}
You can remove columns from the JTable view. The data will still be contained in the TableModel, it just won't be displayed in the JTable.
So the basic code would be:
TableColumnModel tcm = table.getColumnModel();
tcm.removeColumn( tcm.getColumn(...) );
For a more complex solution that allows the user to hide/show columns as they wish check out the Table Column Manager.
I am trying to get the sorted TableModel of a JTable which is done by the following simple regex criteria:
try {
TableRowSorter<TableModel> sortRow = new TableRowSorter<>(testTable.getModel());
testTable.setRowSorter(sortRow);
String sortString = "Something";
sortRow.setRowFilter(RowFilter.regexFilter("(?i)" + sortString));
}
which will sort the data according to sortString.
But when I try to do the following :
try {
TableRowSorter<TableModel> sortRow = new TableRowSorter<>(testTable.getModel());
// ....
// previous code
// ....
TableModel tM = testTable.getModel();
someOtherTestTable.setModel(tM); //<---Here
}
It provides me the DefaultTableModel. So, my question is this: How do I get the sorted TableModel so that I can post to another JTable?
A TableRowSorter conditions the view, JTable; the model, TableModel, remains unchanged. If the underlying model of the RowSorter remains the same, you should be able apply the old TableRowSorter to the new JTable using setRowSorter().
…
someOtherTestTable.setModel(tM);
someOtherTestTable.setRowSorter(sortRow);
I am trying to implement Summation function of MS EXCEL but not getting a way to get the values from the JTable cells. Can you suggest me some way to get the values from the cells and use it for my function?
For example, how can you get the value -
String data[][] = {{"Value1", "Value2", "Value3"},{"Value4", "Value5", "Value6"},
{"Value7", "Value8", "Value9"},{"Value10", "Value11", "Value12"}};
String col[] = {"Column1", "Column2", "Column3"};
DefaultTableModel model = new DefaultTableModel(data, col);
JTable table = new JTable(model);
...
System.out.println(table.getModel().getValueAt(2, 2)); // row index and column index
...
it gives -
Value9
To get the values from the table, you can implement the interface MouseListener in the anonymous inner class, for example -
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
JTable target = (JTable) e.getSource();
int rowIndex = target.getSelectedRow();
int columnIndex = target.getSelectedColumn();
System.out.println(target.getModel().getValueAt(rowIndex, columnIndex));
}
});
See also:
How to Write a Mouse Listener
How to Write a List Selection Listener
I need to take values that I find from inside a for loop to use in a function that isn't inside the loop, and I can't figure out how to do this. What I am hoping to accomplish is to extract values from a key in a hashmap to then plot in a JTable only if that row is selected (using a ListSelectionListener). This way, I can avoid graphing a hundred tables which would save a lot of time. Also I am using DefaultTableModel.
This is my for loop:
tableMaker(model);
for(Map.Entry<String,NumberHolder> entry : entries)
{
//add rows for each entry of the hashmap to the table
double[] v = new double[entry.getValue().singleValues.size()];
int i = 0;
for(Long j : entry.getValue().singleValues)
{
v[i++] = j.doubleValue();
}
//right here I need to take "v"
//and use it in my tableMaker function for that specific row
}
In my tableMaker function, I create my JTable and add a ListSelectionListener, where I hope to create a histogram when a row is selected and add it to my lowerPanel. This is some of the code. I need v so that I can create the dataSet.
public static void tableMaker(DefaultTableModel m)
{
JPanel lowerPanel = new JPanel();
//create table here
frame.getContentPane().add(lowerPanel, BorderLayout.SOUTH);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
JFreeChart chart = ChartFactory.createHistogram(
plotTitle, xaxis, yaxis, dataset, orientation,
show, toolTips, urls);
// lowerPanel.add(chart);
// lowerPanel.revalidate();
}
}
});
}
I sense that you are trying to implement the approach outlined here. Instead of trying to create a new chart each time, create a single chart in a ChartPanel and retain a reference to its XYPlot. In your ListSelectionListener, you can then use plot.setDataset() to update the chart. In this example, a ChangeListener fetches the desired dataset from an existing List<XYDataset>. In this example, a button's ActionListener generates the dataset each time it is called.