I am trying to display the data of hidden column as tooltip. Hiding is working perfectly using the following code:
JTable table = new JTable(model){
//Implement table cell tool tips.
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p);
int colIndex = columnAtPoint(p);
int realColumnIndex = convertColumnIndexToModel(colIndex);
try {
tip = getValueAt(rowIndex, 8).toString();
} catch (RuntimeException e1) {
//catch null pointer exception if mouse is over an empty line
}
return tip;
}
};
TableColumnModel tcm = table.getColumnModel();
TableColumn tc;
for(int i = 1; i <= 7; i++){
tc = tcm.getColumn(8);
tcm.removeColumn(tc);
}
But the tooltip is not showing the data of hidden column (getValue function is not returning value). So do hiding the column delete the data as well ?
You do not need to for loop as you do not use the i variable ;-)
The removeColumn on the JTable does not remove the data from the model, as clearly stated in the javadoc
Removes aColumn from this JTable's array of columns. Note: this method does not remove the column of data from the model; it just removes the TableColumn that was responsible for displaying it.
There is no mention in the javadoc for the same method on the TableColumnModel, but I would assume it works the same way, but you can always give it a try to call it on the JTable instead
The real problem in your code is the use of getValueAt, which uses the row and column index of the table, and not of the model
Note: The column is specified in the table view's display order, and not in the TableModel's column order. This is an important distinction because as the user rearranges the columns in the table, the column at a given index in the view will change. Meanwhile the user's actions never affect the model's column ordering.
And since you removed that column, it simply does not exists for the table. Call the getValue method on the model instead, and do not forget to convert the row index
Related
I am currently using a JTable to display a few patient details. I have a JCheckBox, that when ticked adds a new column to the table and adds the data to the new column. When it is unticked, it should remove the column, sort of like adding extra filters to the table. However, when I tick the box again after unticking it, it duplicates the columns in the table.
I tried to use the fireTableStructureChanged() method, but it would never update the table and so the columns stay there even if the checkbox was unticked. But if I remove it, then when I untick the the checkbox it works, but then the duplication problem comes back. I pasted my actionPerformed() method for when the checkbox is ticked. The first image is of my table before I click my Checkbox. The second is when I click the Checkbox and the column is added. Lastly the third is when I untick the checkbox and tick again. Any help will be much appreciated.
#Override
public void actionPerformed(ActionEvent e)
{
if (gui.getChkCholesterol().isSelected() == true)
{
try {
gui.getRightTableModel().addColumn("Cholesterol");
newColumnIndeces.put("2093-3",gui.getRightTable().getColumnCount()-1);
gui.getRightTableModel().addColumn("Cholesterol Effective Date/Time");
newColumnIndeces.put("2093-3e",gui.getRightTable().getColumnCount()-1);
if(gui.getRightTable().getRowCount()>0)
{
int columnNumberValue = newColumnIndeces.get("2093-3");
int columnNumberDate = newColumnIndeces.get("2093-3e");
for (int i = 0; i<gui.getRightTable().getRowCount(); i++)
{
String value = op.getPatientObservationValue(gui.getRightTable().getValueAt(i,0).toString(),"2093-3");
String date = op.getPatientObservationEffectiveDate(gui.getRightTable().getValueAt(i,0).toString(),"2093-3");
gui.getRightTableModel().setValueAt(value, i, columnNumberValue);
gui.getRightTableModel().setValueAt(date, i, columnNumberDate);
}
}
} catch (ParseException parseException) {
parseException.printStackTrace();
}
setCellColourForTable();
timer.schedule(new RefreshTable(), 0, seconds);
}
else
{
gui.getRightTable().removeColumn(gui.getRightTable().getColumnModel().getColumn(newColumnIndeces.get("2093-3")));
gui.getRightTable().removeColumn(gui.getRightTable().getColumnModel().getColumn(newColumnIndeces.get("2093-3e")-1));
newColumnIndeces.remove("2093-3");
newColumnIndeces.remove("2093-3e");
timer.cancel();
timer = new Timer();
}
gui.getRightTableModel().fireTableStructureChanged();
}
You add a column to the model by using:
gui.getRightTableModel().addColumn("Cholesterol");
This will notify the view that the data has changed and the table will also be updated.
However, you remove the column from the table using:
gui.getRightTable().removeColumn(…);
This only removes the column from the "table view". The column has not been removed from the DefaultTableModel. So the next time you add a column it just gets added to the end of the DefaultTableModel.
So the solution is to remove the column from the DefaultTableModel, not the table.
Unfortunately there is no removeColumn(…) method.
However because your requirement is to only add/remove columns from the end of the DefaultTableModel you can use:
model.setColumnCount(model.getColumnCount() - 2);
which will effectively remove the last two columns from the model.
The other option is to not keep adding columns to the DefaultTableModel, but instead you can just add/remove TableColumns from the TableColumnModel directly. So this would mean the data for the Cholestoral column would always be in the model, but the view would just not display the columns.
So instead of using the model.addColumn(…) you would use the table.addColumn(…) method.
I'm resizing my columns according to their data with the following:
/**
* Set the widths of the columns in the table according to the data in the table.
* #param table
*/
private static void setColumnWidths(JTable table)
{
int columnCount = table.getModel().getColumnCount();
int rowCount = table.getModel().getRowCount();
TableColumnModel columnModel = table.getColumnModel();
for (int col=0; col<columnCount; col++)
{
TableColumn column = columnModel.getColumn(col);
TableCellRenderer renderer = column.getCellRenderer();
if (renderer == null)
{
renderer = new DefaultTableCellRenderer();
}
int overallColumnWidth = 0;
for (int row = 0; row < rowCount; row++)
{
Object value = table.getValueAt(row, col);
Component component = renderer.getTableCellRendererComponent(table, value, false, false, row, col);
int componentWidth = (int) component.getPreferredSize().getWidth();
overallColumnWidth = Math.max(componentWidth, overallColumnWidth);
}
column.setPreferredWidth(overallColumnWidth);
}
}
This works when all the columns are visible, but I've got code that hides some of them (JTable.removeColumn(TableColumn column)). It appears that both the JTable instance and the TableColumnModel instance have the list of data columns, i.e., all columns regardless of visibility. How can I get a list of only columns that are visible, or test whether a given column is visible?
(I've searched for this, but get longs lists of articles on how to hide the columns, and no explanation of where the visible/invisible information is kept. I thought, since I asked the JTable to hide the column, that somewhere in there it would know which columns were hidden and I could get that info.)
Check if table.convertColumnIndexToView(col) returns -1.
From the documentation:
public int convertColumnIndexToView(int modelColumnIndex)
Maps the index of the column in the table model at modelColumnIndex to
the index of the column in the view. Returns the index of the
corresponding column in the view; returns -1 if this column is not
being displayed. If modelColumnIndex is less than zero, returns
modelColumnIndex.
Source
The problem with your code if that your loops is controlled by the values returned in the TableMdoel.
Instead you should be using values from the table:
int rowCount = table.getRowCount();
int columnCount = table.getRowCount();
Then there is no need for exception logic to determine if a column is visible or not because by default it will be visible because it is the job of the view (JTable) to only display visible columns.
You need to understand the difference between the "view" and the "model".
how do I determine which columns in a JTable are visible
So the better answer is to use the methods of the JTable. Your current solution confuses the view and model.
You could also use the Table Column Adjuster to do the column adjustment for you. It provides features like dynamically resizing the column as the data changes.
I have a JTable and any single row in it has associated a different tooltip when mouse hover a row. I have created a "filter" for this table; when it is applied it perfectly hides the rows need to be hidden but when I hover the mouse on the filtered rows, looks like the tooltip is referring to the row that occupied the same row position of the new current row.
For example:
Table
ROW 1 -> tooltip 1
ROW 2 -> tooltip 2
Apply Filter to Table:
ROW 2 -> tooltip 1
So ROW 2 is displaying the tooltip 1 instead of 2.
TableRowSorter<TableModel> sorter = (TableRowSorter<TableModel>) table.getRowSorter();
sorter.setRowFilter(RowFilter.regexFilter(text));
My table that extends JTable has:
#Override
public String getToolTipText(MouseEvent e) {
final int rowIndex = rowAtPoint(e.getPoint());
TableModel model = getModel();
// take the value from the first column of the selected row
String tip = (String) getModel().getValueAt(rowIndex, 0));
return tip;
}
So it looks like using the model is not (quite obvious) updated respect to the filter. I tried using TableModel model = getRowSorter().getModel() too but without any luck.
How can I point to a correct "filtered model" to retrieve the correct row position?
UPDATE:
I have replaced the "rowIndex" code like this:
final int rowIndex = convertRowIndexToModel(rowAtPoint(e.getPoint()));
It partially solves the problem, but when some rows are added dynamically to the table with the filter applied and I hover new rows I get the exception (with relative API description):
IndexOutOfBoundsException -> if sorting is enabled and passed an index outside the range of the JTable as determined by the method getRowCount
You need to convert the views row index to the model's row index
Have a look at JTable#convertRowIndexToModel
You should not override that JTable#getToolTipText method. Just set the tooltip-text on the component returned by your renderer. The JTable will pick it up automatically. You can see this in the implementation of the getTooltipText method of the JTable
I would like to know if it's possible to view my values through JTable and then edit them through there?
isCellEditable(int row, int col)
This method determines which rows and columns the user is allowed to modify. Since this method returns a Boolean, if all cells are editable it simply returns a true. To prevent a JTable from editing a particular column or row value, it returns a false from this method. The following code enables only column one to display while allowing the rest of the columns to be modified.
// Make column one noneditable
while allowing the user to edit at
all // other columns.
If (col == 1){
return false;
}
else{
return true;
}
public void setValueAt(Object value, int row, int col)
When the user makes changes to an editable cell, the Table Model is notified via this method. The new value, as well as the row and column it occurred in, is passed as arguments to this method. If the original data is coming from a database, this method becomes important. As you'll see, data retrieved from a database is held locally within the Table Model, usually as vectors. When the user changes a cell value in a JTable, the corresponding data in the Table Model isn't automatically changed. It's your responsibility to add code in this event to ensure that the data in the Table Model is the same as the data in the JTable. This becomes important when code is added to update the database. The following code updates the data (held in an array of objects) in the Table Model with the new value that the user just entered in the JTable.
// Update the array of objects with
// the changes the user has just entered in a cell.
// Then notify all listeners (if any) what column
// and row has changed. Further processing may take place there.
rowData[row][col] = value;
fireTableDataChanged();
Sure it's possible just have TableModel.isCellEditable() return true, and if necessary set a TableCellEditor.
Yes it is possible.Basically the jtable is editable.you can check through the TableModel.isCellEditable() method. After editing it you can store the table value in the two dimensional array and store in database.
int i;
int j;
String tableData = new String[row count][column count];
for(i = 0; i < row count; i++)
{
for(j = 0; j < 3; j++)
{
tableData[i][j] = table.getValueAt(i, j).toString();
}
}
I have an application, and I would like to print a JTable, but since it has many columns, I would like user to select/limit which columns to print so it can fit in regular printer paper.
I'm using JTable.print() function to print. (http://java.sun.com/docs/books/tutorial/uiswing/misc/printtable.html)
Right now, my solution, is to create another JTable with the columns that user selected, then repopulate the table with the data, then send it to printer.
Is there a better way to do it?
As I've answered here, I solved it by hiding columns before printing and restoring columns after printing:
// get column num from settings
int num = gridSettings.getColumnsOnPage();// first <num> columns of the table will be printed
final TableColumnModel model = table.getColumnModel();
// list of removed columns. After printing we add them back
final List<TableColumn> removed = new ArrayList<TableColumn>();
int columnCount = model.getColumnCount();
// hiding columns which are not used for printing
for(int i = num; i < columnCount; ++i){
TableColumn col = model.getColumn(num);
removed.add(col);
model.removeColumn(col);
}
// printing after GUI will be updated
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// table printing
try {
table.print(PrintMode.FIT_WIDTH, null, null, true, hpset, true); // here can be your printing
} catch (PrinterException e) {
e.printStackTrace();
}
// columns restoring
for(TableColumn col : removed){
model.addColumn(col);
}
}
});
For printing specific part of a JTable, just change a little bit this code.
The best way: just set column width to zero then it will be hidden:)
TableColumn column = table.getColumnModel().getColumn(i);
//backup first
int minWidth=column.getMinWidth();
int width=column.getPreferredWidth();
//to hide:
column.setMinWidth(0);
column.setPreferredWidth(0);
//to show it back:
column.setMinWidth(minWidth);
column.setPreferredWidth(width);