JXTable - how to update highlighters on sorting the table - java

I have a JXTable with custom table model. I added 2 ColorHighlighter's with custom HighlightPredicate's.
Problem is when i click on the column header, the table sorts the rows, BUT the highlighter's remain as for the old view.
How can I update the state of the highlight after sorting a table?

As #kleopatra mentioned, i looked at my predicate:
HighlightPredicate spakowany = new HighlightPredicate() {
#Override
public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
TableModel tableModel = table.getModel();
if (tableModel instanceof StanTableModel) {
StanTableModel stanTableModel = (StanTableModel) tableModel;
// int rowIndex = adapter.row; <- this was the issue
int rowIndex = adapter.convertRowIndexToModel(adapter.row);
StanTableRow myCustomRow = stanTableModel.getRow(rowIndex);
if ((myCustomRow.isSpakowany()) {
return true;
}
}
return false;
}
};
and used #mKorbel idea:
was:
int rowIndex = adapter.row;
is now:
int rowIndex = adapter.convertRowIndexToModel(adapter.row);
And it works now.
StanTableModel is my custom table model. It has getRow() function and returns a StanTableRow object which in turn has isSpakowany() function.

Related

Set tooltip for cells in jTable without overriding getToolTipText()

I am making gui with the NetBeans GUI Builder(Swing) and need to set different tooltips for each cells in the header. The problem is that jTable is generated automatically, so I can't override its methods.
Is there any possibility to do it without the overriding getToolTipText()?
One way to do this sort of thing is to add a subclass which extends the MouseMotionAdapter and a method to your code to carry out the task for you. Simply place the following SubClass code below the end of your main Class.
class JTableColumnHeaderToolTips extends MouseMotionAdapter {
TableColumn curCol;
// Create a Map to hold the Header Column
// index value and the tooltip related to
// it.
Map headerColumnTips = new HashMap();
// Method to Set tips into Map.
public void setHeaderColumnToolTip(TableColumn column, String tooltip) {
if (tooltip == null) {
headerColumnTips.remove(column);
}
else {
headerColumnTips.put(column, tooltip);
}
}
// Override the Header's mouseMoved event so as
// to display the appropriate tooltip for whatever
// column the mouse pointer is currently on.
#Override
public void mouseMoved(MouseEvent event) {
JTableHeader header = (JTableHeader) event.getSource();
JTable table = header.getTable();
TableColumnModel colModel = table.getColumnModel();
int colIndex = colModel.getColumnIndexAtX(event.getX());
TableColumn column = null;
if (colIndex >= 0) {
column = colModel.getColumn(colIndex);
}
if (column != curCol) {
header.setToolTipText((String) headerColumnTips.get(column));
curCol = column;
}
}
}
Then add this method setJTableColumnToolTips() somewhere within your main Class:
private void SetJTableHeaderColumnToolTips(JTable table, String[] columnToolTips) {
JTableHeader tableHeader = table.getTableHeader();
// See the JTableColumnHeaderToolTips SubClass.
JTableColumnHeaderToolTips toolTips = new JTableColumnHeaderToolTips();
for (int col = 0; col < table.getColumnCount(); col++) {
TableColumn columnIndex = table.getColumnModel().getColumn(col);
toolTips.setHeaderColumnToolTip(columnIndex, columnToolTips[col]);
}
tableHeader.addMouseMotionListener(toolTips);
}
To use this method you might do it this way:
// Provide the Tooltips you want for
// each column within a String Array.
String[] columnToolTips = {"First Name",
"Last Name",
"The person's address",
"The person's phone number",
"The person's age",
"The person's salary"};
// Set your desired ToolTips to the Header Column cells
setJTableHeaderColumnToolTips(recordsTable, columnToolTips);

How to select a column of a JTable in JDialog by selecting a header

What I've been trying to do with a JDialog are...
To select a column of JTable by clicking the header
To check which column is selected by the user
To get the value of the cells inside the column
According to this post and this page , it would be possible to select a column by clicking the header, by setting a JTableHeader.
However, neither of them seem to be applicable to what I'm trying to do.
First of all, I'm not sure where to put JTableHeader. The examples above seem to have put it for the initialization, but I don't see any appropriate space to do this in my coding.
At least I know that the second example is JPanel. So, in order to have a JTableHeader in JDialog, JTableHeader will need to be set in a completely different position, since initComponents() of JDialog cannot be modified manually by default.
In addition, I cannot find how to select a header (unlike individual cells). I assume that I need to set a JTableHeader beforehand.
Finally, I don't see any method to detect which column is selected. At least I found jTable.getValueAt(int, int) method, but this method seems to be made to get a single cell.
Now I suspect that it might be impossible to do them with JTable and JDialog. I'd appreciate if you'd give any insight.
I add a part of initComponents() so that you'd easily understand it.
private void initComponents() {
//here are irrelevant codes
jTable1 = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
jLabel1.setFont(new java.awt.Font("MS UI Gothic", 3, 18)); // NOI18N
jLabel1.setText("Choose level(s) or unit(s)");
//irrelevant codes
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{"EN6", "EN3", "EN5", "IN1"},
{"EN2", "EN3", null, "IN4"},
{null, null, null, "IN1"},
{null, null, null, "IN2"},
new String [] {
"EN2", "EN3", "EN5", "IN1"
}
) {
Class[] types = new Class [] {
java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
};
public Class getColumnClass(int columnIndex) {
return types [columnIndex];
}
});
//lots of lines, seem to be irrelevant
pack();
}
"[...]it would be possible to select a column by clicking the header, by setting a JTableHeader."
Based on your requirements I don't think you need to provide your own table header but attach a MouseListener to the default one instead. This way and using both rows and columns selection models you can easily achieve your goal.
Snippet
final JTable table = new JTable(tableModel);
table.setColumnSelectionAllowed(true);
table.getTableHeader().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// Get the right column based on MouseEvent#getPoint()
int columnIndex = table.columnAtPoint(e.getPoint());
// Set this column as the selected one in the columns selection model
table.getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
// Set all the rows as the selected ones in the rows selection model
table.getSelectionModel().setSelectionInterval(0, table.getRowCount() - 1);
// Print the values in selected column
for (int rowIndex = 0; rowIndex < table.getRowCount(); rowIndex++) {
System.out.println(table.getValueAt(rowIndex, columnIndex));
}
}
});
Note: don't forget to allow columns selection.
See:
MouseEvent#getPoint()
JTable#columnAtPoint(Point p)
JTable#rowAtPoint(Point p)
How to Use Tables: User Selections
You can get the select cell's value using this. But is that right you want?
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if (arg0.getClickCount() == 1) { // 1 : one click, 2 : double click, 3 : right click
int column = table.getSelectedColumn();
int row = table.getSelectedRow();
String str = (String) table.getValueAt(row, column);
int[] rows = table.getSelectedRows();
String str2 = (String) table.getValueAt(rows[0], column);
}
}
});

How to add rows on a JTable using AbstractTableModel?

I have a JTable with my own Model (extends AbstractTableModel), and I'd like to add a row to it when I Click a JButton.
I don't really know how to hadd the row to the Model.
here is my model:
public class MembersModel extends AbstractTableModel {
String[] columnNames = {
"Name",
"Money Spent",
"Percent",
"Current Deck"
};
Object[][] data = {
{"Cajo", new Integer(150), new Integer(0), "Event Deck"},
{"Sekiam", new Integer(200), new Integer(0), "Jeskay"},
{"Nuvas", new Integer(100), new Integer(0), "Big Shit"},
{"Dos", new Integer(100), new Integer(0), "Crap Deck"},
{"Atoj", new Integer(100), new Integer(0), "IDK"}
};
public MembersModel(){
super();
calcAllPercent();
}
public void calcAllPercent(){
for(int i = 0; i < data.length; ++i){
data[i][2] = calcPercetage((Integer) data[i][1]);
}
}
private int calcPercetage(int money){
return (money*100)/teamMoneySpent();
}
private int teamMoneySpent(){
int money = 0;
for(int i = 0; i < data.length; ++i){
money += (Integer) data[i][1];
}
return money;
}
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public String getColumnName(int col) {
return columnNames[col];
}
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) {
return false;
}
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
calcAllPercent();
fireTableRowsUpdated(0, 4);
}
}
Should i create my table aswell or add the method to the Model?
The key will be the data nucleus that you're using for your model, which here is your 2-D array, Object[][] data. The question then boils down to this: how do you add another row to the array and then notify the model's listener of the addition. While this can be done by creating a new data array with another row, copying all the data from this array, and adding the new data to the newly added row, why bother? For my money I'd
create a class to hold the data of a single table row, here I'll call it MyType, but you'll give it a better name, and it will have String, int, int, and String fields to correspond to the columns of your table.
Give this class some of the methods you have in your model above, such as doing row-specific calculations, calcPercentage(..), teamMoneySpent(...), and then the model can call the row object's method when this information is needed.
use an ArrayList<MyType> as my table model data nucleus, not a 2-dimensional hard-coded array.
give my model class an addRow(MyType myObj) method
in the method add to the ArrayList
and then call the appropriate model notification method, which here would be fireTableRowsInserted(...).
Note, I'm not sure what you mean by,
Should i create my table aswell or add the method to the Model?
Some problems with your current model:
The setValueAt() method is wrong. You should invoking tableCellUpdated(...). You don't want to repaint the data in the entire table when you update a single cell. Actually you don't even need to implement the setValueAt(...) method because your table is not editable.
You didn't override the getColumnClass(...) method. This method is required so the table can use the proper renderer to display the data.
Instead of creating a completely new TableModel, you could extend the DefaultTableModel. It already supports an addRow(...) method.
However, as hovercraft has already pointed out a better design is create a custom Object to store all the data of a single row. For a solution that uses this approach check out Row Table Model for a solution. The base TableModel is more complicated, but it makes it easier to create custom TableModels in the future since all the common code is in one class.
I would implement hovercraft's suggestion first so you better understand the concepts of creating a TableModel with a custom Object. I include this link as a suggestion for the future.

dynamically changing the width of the column in jtable with Netbeans IDE

Developing an application in netbeans and java swing
I want to change the width of my columns in a jtable
to adjust to the length of data in the cell
aftr a google search i stumble upon Binklye's blog
on the following link
http://binkley.blogspot.com/2006/01/getting-jtable-columns-widths-to-fit.html
below are code snippets
{
final TableCellRenderer renderer = getTableHeader()
.getDefaultRenderer();
for (int i = 0; i < getColumnCount(); ++i)
getColumnModel().getColumn(i).setPreferredWidth(
renderer.getTableCellRendererComponent(this,
getModel().getColumnName(i), false, false, 0, i)
.getPreferredSize().width);
}
public Component prepareRenderer(final TableCellRenderer renderer,
final int row, final int column) {
final Component prepareRenderer = super
.prepareRenderer(renderer, row, column);
final TableColumn tableColumn = getColumnModel().getColumn(column);
tableColumn.setPreferredWidth(max(
prepareRenderer.getPreferredSize().width,
tableColumn.getPreferredWidth()));
return prepareRenderer;
}
will love to have someone help with the implementation of the codes.
On the other hand if there is another soution , will be glad to have a look at it.
Check out Table Column Adjuster.
Try this one:
jtable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
You can write your own custom method which will be fired when you add row or delete it.
Sample code:
public static void resizeRow(JTable table) {
TableColumnModel columnModel = table.getColumnModel();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
TableColumn column = columnModel.getColumn(i);
column.setPreferredWidth(/*your logic of setting width*/);
}
}

String path displayed when adding Image in JTable

I tried using setValueAt in adding an image but the problem is it prints the string and does not load the image. any help on this. the code is below
int selectedColumn = table1.getSelectedColumn();
int selectedRow = table1.getSelectedRow();
ImageIcon addIcon = new ImageIcon("c:\\onion.png");
table1.getModel().setValueAt(addIcon, selectedRow, electedColumn);
You need to create a table model which returns Icon.class for its getColumnClass method.
Ensure that your table knows what data is stored in a given column so it can choose the appropriate renderer. So, your JTable creation code should be something like this:
DefaultTableModel tableModel = new DefaultTableModel(dataObject, columnNames);
JTable table = new JTable(tableModel){
public Class getColumnClass(int column){
return getValueAt(0, column).getClass();
}
};

Categories