I have a simple Swing JTable and a TableRowSorter made by me. However, I would exclude the first column from the sorting, as I want to keep it to show row numbers.
I can't see to find anything, except
sorter.setSortable(0, false);
Which makes the column not clickable, but still sortable when another column is clicked...
So quick question will be: how to keep a column from being sorter by a TableRowSorter?
Thank you!
So, with a JTable (ex below) sorting on column A would produce the following. However, you want the data to sort, but not the row numbers, correct?
|row| column A | |row| column A |
+---+-----------+ +---+-----------+
| 1 | blah blah | --> | 1 | blah blah |
| 2 | something | | 3 | more blah |
| 3 | more blah | | 2 | something |
I would approach this with a TableCellRenderer for column 0. The trick is to ignore the value passed and instead use the row parameter.
public class RowRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object color,
boolean isSelected, boolean hasFocus, int row, int column) {
setText(Integer.toString(row));
return this;
}
}
Note: if you are paginating your table (ie the model does not contain all of the rows; for example only rows 100-200) you will need to advise the cell renderer of the amount to add to row to obtain the row number to display.
A JTable is designed around displaying rows of data, not cells of data, so it isn't really possible to prevent an individual column from sorting, as you put it. Instead I would try modifying your TableModel to return the row index for the value for that column:
#Override public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) return rowIndex;
else {
// handle other columns
}
}
If that doesn't work you could also try modifying the table cell renderer to use the table row index instead.
If the row number isn't part of the data, then it should not be stored in the model.
Instead I would use a row header that displays a row number. Something like you would see in Excel. You can use the Row Number Table for this.
Related
I have a Jtable set up in a tabbed pane that is filled with an id and checkboxes. The table looks something along the lines of this, where . are the checkboxes.
| VAR1 |
ID | ALL | subVar1 | subVar2 |
------------------------------
id1| . | . | . |
Now, I also have a TableListener attached to this table. What I would like to happen is that, whenever a user presses the ALL checkbox, all the checkboxes in that row need to be selected (ie true). This is the table listener code.
#Override
public void tableChanged(TableModelEvent e) {
if(e.getSource() == assignedTableModel) {
for (int i = 0; i < aTable.getRowCount(); i++) {
boolean isAllChecked = (Boolean) aTable.getValueAt(i, 1);
if(isAllChecked) {
assignedTableModel.setValueAt(Boolean.TRUE, i, j);
}
else {
...
}
}
}
}
Clicking the ALL checkbox causing the table to change, assignedTableModel.setValueAt(Boolean.TRUE, i, j); is called, the table is changed again and therefore calls the listener, which calls this function again.
My question, is there another way of updating the checkboxes? Or is there a way to set a base to get out of the recursion?
EDIT The rows are added dynamically. I'm wondering if adding an actionListener to the ALL checkbox as it's being added will be a solution. I'll come back with how it turns out.
EDIT2 I'd forgot to mention that the whole table is generated dynamically. That means I have no way of knowing how many columns and rows will be present, the only columns I know are ID and the ALL col. Most answers already present deal with hard coded implementations.
whenever a user presses the ALL checkbox, all the checkboxes in that row are selected
So why are you looping through all the rows in your code? The event will be generated only for the row you click and you only need to select the check marks for the columns on that row. Get rid of the looping code.
the table is changed again and therefore calls the listener, which calls this function again.
You need an if condition to identify when the check box in the first column is checked:
if (e.getType() == TableModelEvent.UPDATE)
{
int row = e.getFirstRow();
int column = e.getColumn();
if (column == 0)
{
TableModel model = (TableModel)e.getSource();
model.setValueAt(Boolean.true, row, 1);
...
}
}
Now the change of state on the other columns will be ignored.
Based off of #camickr's response, the following piece of code seems to be doing the trick. Thanks.
#Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE && e.getSource() == assignedTableModel)
{
int row = e.getFirstRow();
int column = e.getColumn();
if (column == 1)
{
DefaultTableModel model = (DefaultTableModel) e.getSource();
for(int i=2 ; i<model.getColumnCount() ; i++) {
if((boolean) model.getValueAt(row, 1))
model.setValueAt(Boolean.TRUE, row, i);
else
model.setValueAt(Boolean.FALSE, row, i);
}
}
}
}
I create a simple JTable with TableModel, and I hidden the first column.
I set at my JTable also the TableRowSorter
This is the code that I use to create a table
tableModelArticoliVendere = new MyTableModelDescrizioneArticoli();
tableArticoliVendere = new CustomTableArticoliDaVendereBar(tableModelArticoliVendere);
sorter = new TableRowSorter<MyTableModelDescrizioneArticoli>(tableModelArticoliVendere);
tableArticoliVendere.setRowSorter(sorter);
tableArticoliVendere.addMouseListener(new MyMouseAdapterArticoliDaVendere());
tableArticoliVendere.removeColumn(tableArticoliVendere.getColumnModel().getColumn(0));
If the user click on the one row of the table the mouse listenere are called.
This is the method:
public class MyMouseAdapterArticoliDaVendere extends MouseAdapter {
public void mouseClicked(MouseEvent me) {
JTable t = (JTable)me.getSource();
if (me.getClickCount() == 1) {
String codiceArticolo =((JTable)tableArticoliVendere).getModel().getValueAt(t.getSelectedRow(), 0).toString();
inserisciProdotto(codiceArticolo);
}
}
}
The problem is this:
If I see the complete table and I clik on the one of the row table, I read the codiceArticolo right. If I use the row filter, and I try to click on the first row I have an error.
I have the table with 3 row for example:
TABLE
column 0| column 1
------------------
valore1 | 1
valore2 | 2
valore3 | 3
If I use the filter I have this situation:
TABLE
column 0| column 1
------------------
valore2 | 2
valore3 | 3
if I try to click on the first row, the value of codiceArticolo is valore1 and not valore2.
If I not hidden the column 0, I don't have this error.
When you have sorting or filtering enabled in your table, the indexes of table rows and columns stop lining up with indexes of the model rows and columns. You can account for this using convertRowIndexToModel and convertColumnIndexToModel.
For instance, when you use t.getSelectedRow(), you can adjust like this:
int tableRowIndex = t.getSelectedRow();
int modelRowIndex = t.convertRowIndexToModel(tableRowIndex);
It will also help if you indicate in your code when you are using view indexes and when you are using model indexes.
I currently have a populated SWT table with the following styles:
SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL
used SWT.FULL_SELECTION to get the whole line selected if clicked.
but using table.getSelection() only returns the first column.
I don't have any tableviewer or something else set.
where did I make a mistake?
edit:
example:
if (table.getSelectionCount() > 0) {
for (TableItem item : table.getSelection()) {
System.out.println(item);
}
}
this returns only the first column
Since you are only calling System.out.println() on the whole TableItem, Java will internally use TableItem#toString() to convert it to a String.
The resulting string however, will not contain all the data of the TableItem.
Instead, you'll need to iterate over the columns to get the data using TableItem#getText(int column):
for(int i = 0; i < table.getColumnCount(); i++)
System.out.println(item.getText(i));
I'm looking for a way to disallow the selection or focusing of some cells (neither a complete column or row) in a JTable.
For example: I have a very tiny table with 2 rows and 2 columns and i only want the cells (0,0) and (1,1) to be selectable and focusable, while the cells (1,0) and (0,1) can not be selected or focused.
Does someone know how to achieve this behavior? So far i only found the way to implement a custom ListSelectionModel. But it only works for columns or rows (two different models).
Try overriding JTable's changeSelection method with you custom constraints and you'll likely need to disable editing via overriding isCellEditable too. E.g.:
final JTable table = new JTable( data, columnNames ) {
#Override
public void changeSelection( int row, int col, boolean toggle, boolean expand ) {
if( ( row + col )%2 == 0) { // here you set your own rules
super.changeSelection( row, col, toggle, expand );
}
}
#Override
public boolean isCellEditable( int row, int col ) {
return false; // disabling editing separately
}
};
I have a JTable with 3 column of which first column is a button and second column is id. Now when user clicks on the button of specific row that row should be deleted. Up to this point everything wo$rks fine. But another requirement is re-sequencing the table data. I mean the column id should be re-sequence. For example:
First table data:
| id | another-column
b1 | 1 | abc
b2 | 2 | xyz
b3 | 3 | def
b4 | 4 | qwe
Now when user deletes second row which have id=2 then table data should be as follows:
| id | another-column
b1 | 1 | abc
b3 | 2 | def
b4 | 3 | qwe
Here b1/b2/b3/b4 are buttons for deletion of particular row.
How can I do this?
It is fairly easy to set this sequential id value inside the getValueAt(row, col) of your Abstract Table Model.
public Object getValueAt(int row, int col) {
if (col == 1)
return int (row + 1);
.....
}
Set the model again inside the action event of your buttons. The model will repaint the JTable correctly after a button has been pressed.