JTable row hightlighter based on value from TableCell - java

as I read that not possible to Encode my Navajo language
finging the way how to only alternate/striped Color into JTable (example #camickr)
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TableRowRenderingTip extends JPanel {
private static final long serialVersionUID = 1L;
public TableRowRenderingTip() {
Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"};
Object[][] data = {
{"Buy", "IBM", new Integer(1000), new Double(80.5), Boolean.TRUE},
{"Sell", "Dell", new Integer(2000), new Double(6.25), Boolean.FALSE},
{"Short Sell", "Apple", new Integer(3000), new Double(7.35), Boolean.TRUE},
{"Buy", "MicroSoft", new Integer(4000), new Double(27.50), Boolean.FALSE},
{"Short Sell", "Cisco", new Integer(5000), new Double(20), Boolean.TRUE}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Alternating", createAlternating(model));
add(tabbedPane);
}
private JComponent createAlternating(DefaultTableModel model) {
JTable table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (!isRowSelected(row)) { // Alternate row color
c.setBackground(row % 2 == 0 ? getBackground() : Color.LIGHT_GRAY);
}
return c;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
return new JScrollPane(table);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(false);
JFrame frame = new JFrame("Table Row Rendering");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TableRowRenderingTip());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I have a JTable which contains some market trades (better for understanding by reason my poor English skills), but some of deals has only one leg, but another (for example vanilla Cross Currency Swap) could have two legs. How is possible to hightlighting TableRows based on value from specifics TableColumn (for example last column with name DealId). I tried to check row with row - 1 && row + 1, but my empty head generated lots of codesRow, to much for idea how to stop complicated simple simple things, how to check if there exist duplicate value in another row (always with strict ordering as captured in the pictures). No idea how to implements simple formula for that
pictures demonstrated:
generated from code:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TablePrepareRenderer extends JFrame {
private static final long serialVersionUID = 1L;
private Object[] columnNames = {
"Buy/Sell", "Type", "SubType", "Ccy1", "Amount1", "Ccy2", "Amount2", "DealId"};
private Object[][] data = {
{"Buy&Sell", "Ccy Swap", "A1", "EUR", new Double(1000000.00), "USD", new Double(1439000.00), 50},
{"Buy&Sell", "Ccy Swap", "A3", "USD", new Double(1438900.00), "EUR", new Double(1000000.00), 50},
{"Buy&Sell", "Ccy Swap", "A1", "EUR", new Double(500000.00), "CHF", new Double(550000.00), 350},
{"Buy&Sell", "Ccy Swap", "A1", "CHF", new Double(549800.00), "EUR", new Double(500000.00), 350},
{"Sell&Buy", "Ccy Swap", "A3", "USD", new Double(1000000.00), "EUR", new Double(749000.00), 2250},
{"Sell&Buy", "Ccy Swap", "A1", "EUR", new Double(748900.00), "USD", new Double(1000000.00), 2250},
{"Buy&Sell", "Ccy Swap", "A1", "GBP", new Double(1000000.00), "USD", new Double(1638100.00), 400},
{"Buy&Sell", "Ccy Swap", "A3", "USD", new Double(1638200.00), "GBP", new Double(1000000.00), 400},
{"Sell", "Ccy Spot", "A1", "AUD", new Double(343575.0), "EUR", new Double(250000.0), 11990},
{"Buy", "Ccy Spot", "A1", "EUR", new Double(100000.00), "JPY", new Double(1099000.00), 259},
{"Sell", "Ccy Fwd", "A3", "DKK", new Double(74889.00), "EUR", new Double(10000.00), 115439},};
private JTable table;
public TablePrepareRenderer() {
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) c;
/*if (!isRowSelected(row)) {
c.setBackground(getBackground());
int modelRow = convertRowIndexToModel(row);
String type = (String) getModel().getValueAt(modelRow, 0);
if (("Buy".equals(type)) && !("Buy&Sell".equals(type))) {
c.setBackground(Color.orange);
} else if (("Sell".equals(type)) && !("Sell&Buy".equals(type))) {
c.setBackground(Color.orange);
} else if ("Buy&Sell".equals(type)) {
c.setBackground(Color.yellow);
} else if ("Sell&Buy".equals(type)) {
c.setBackground(Color.yellow);
}
}*/
/*if (!isRowSelected(row)) {
if (row == 0 ||row == 1||row == 4||row == 6||row == 7||row == 9||row == 10) {
((JComponent) c).setBackground(Color.orange);
} else {
((JComponent) c).setBackground(Color.yellow);
}
}*/
if (!isRowSelected(row)) {
if (row == 0 || row == 1 || row == 4 || row == 5 || row == 8 || row == 10) {
((JComponent) c).setBackground(Color.orange);
} else {
((JComponent) c).setBackground(Color.yellow);
}
}
if (column == 0 || column == 1 || column == 2 || column == 3 || column == 5) {
//setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
//c.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
//(JComponent) c.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
}
return c;
}
#Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return String.class;
case 3:
return String.class;
case 4:
return Double.class;
case 5:
return String.class;
case 6:
return Double.class;
case 7:
return Integer.class;
}
return null;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane);
}
public static void main(String[] args) {
TablePrepareRenderer frame = new TablePrepareRenderer();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Edit:
how to set Alignment for TableCell into prepareRenderer,

how to set Alignment for TableCell into prepareRenderer,
This should NOT be done in the prepareRenderer code. This property should be set in the renderer for the class or for the column because it only applies to a specific class or renderer. Instead use:
table.setPreferredScrollableViewportSize(table.getPreferredSize());
DefaultTableCellRenderer stringRenderer = (DefaultTableCellRenderer)table.getDefaultRenderer(String.class);
stringRenderer.setHorizontalAlignment( SwingConstants.CENTER );
For the highlighting code I used code that assumes that the dealld value is unique for a given set of transactions:
private Map<Object, Color> rowColor = new HashMap<Object, Color>();
private Color nextColor = Color.ORANGE;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) c;
if (isRowSelected(row)) return c;
Object value = table.getValueAt(row, 7);
Color background = rowColor.get(value);
if (background != null)
{
c.setBackground( background );
}
else
{
rowColor.put(value, nextColor);
c.setBackground( nextColor );
nextColor = (nextColor == Color.ORANGE) ? Color.YELLOW : Color.ORANGE;
}
return c;
}
Note: It won't work if sorting is required.
Here is another approach that should work even if sorting is required (but I didn't test it with sorting);
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) c;
if (!isRowSelected(row))
{
c.setBackground(getRowBackground(row));
}
return c;
}
private Color getRowBackground(int row)
{
boolean isDark = true;
Object previous = getValueAt(0, 7);
for (int i = 1; i <= row; i++)
{
Object current = getValueAt(i, 7);
if (! current.equals(previous))
{
isDark = !isDark;
previous = current;
}
}
return isDark ? Color.ORANGE : Color.YELLOW;
}

it's Sunday, wheather detoriating, so couldn't resist to show the SwingX version. It's the same logic as #camickr 2nd, thanks :-)
Advantages:
code can focus on logic as the value retrieving handles sorting/filtering/column moves automagically
knows about default ui alternate striping colors (and updates on switching the LAF)
Highlighter support is built-in, no need to subclass the table nor care about renderer misbehaviour
easy to add additional highlighters (yelling sell, sell, sell :-)
The code snipped:
JXTable table = new JXTable(data, columnNames);
HighlightPredicate predicate = new HighlightPredicate() {
#Override
public boolean isHighlighted(Component renderer,
ComponentAdapter adapter) {
if (adapter.row == 0) return false;
return isOddValue(adapter);
}
private boolean isOddValue(ComponentAdapter adapter) {
Object previous = adapter.getFilteredValueAt(0, 7);
boolean odd = false;
for (int i = 1; i <= adapter.row; i++) {
Object current = adapter.getFilteredValueAt(i, 7);
if (!previous.equals(current)) {
odd = !odd;
}
previous = current;
}
return odd;
}
};
table.addHighlighter(new UIColorHighlighter(predicate));

Related

Trying to get the sorter positon to retain after a table refresh

I have the following method:
private void passStingR(StringBuilder retVal) throws BadLocationException {
int scrollPositionR = scrollR.getVerticalScrollBar().getValue();//get value of scroll position stores in javas memory
windowR.remove(scrollR);
tableR.getModel();
modelR.setRowCount(0);
Document docR = null;
try {
docR = loadXMLFromString(retVal.toString());//pull in the XML data into a new doc
} catch (Exception ex) {
Logger.getLogger(remit.class.getName()).log(Level.SEVERE, null, ex);
}
populate1R(docR);
tableR.getTableHeader().setReorderingAllowed(false);//prevent user from changing column order now at refresh level
SimpleDateFormat time_formatterR = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String current_time_strR = time_formatterR.format(System.currentTimeMillis());
updatetFieldR.setText(current_time_strR);
scrollR.remove(tableR);
tableR = new JTable(modelR)
{
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
Font myFont = new Font("Arial",Font.PLAIN,10);
Font myFont1 = new Font("Arial", Font.BOLD,10);
if (!isRowSelected(row)) {
if (tableR.getColumnCount() >= 0) {
String type = (String) getModel().getValueAt(row, 11);
c.setBackground("0.0".equals(type) ? Color.RED : Color.WHITE);
c.setForeground("0.0".equals(type) ? Color.WHITE : Color.BLACK);
c.setFont("0.0".equals(type) ? myFont1: myFont);
}
}
return c;
};
};
TableColumn column = null;
for (int i = 0; i < 18; i++) {
column = tableR.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(70); //sport column is bigger
}
if (i == 1) {
column.setPreferredWidth(500); //sport column is bigger
}
if (i == 7) {
column.setPreferredWidth(30); //sport column is bigger
}
if (i == 8) {
column.setPreferredWidth(20); //sport column is bigger
}
if (i == 9) {
column.setPreferredWidth(25); //sport column is bigger
}
if (i == 14) {
column.setPreferredWidth(500); //sport column is bigger
}
if (i == 15) {
column.setPreferredWidth(10); //sport column is bigger
}
if (i == 16) {
column.setPreferredWidth(20); //sport column is bigger
}
}
tableR.getTableHeader().setReorderingAllowed(false);//prevent the user from sorting the columns at intialise GUI stage even though the user cannnot change this
RowSorter<TableModel> sorter = new TableRowSorter<>(modelR);//creating a new sorter here from my modelR
tableR.setRowSorter(sorter);//set the sorter positon
scrollR = new JScrollPane(tableR);
windowR.add(scrollR);
windowR.validate();
scrollR.getVerticalScrollBar().setValue(scrollPositionR);
}
I then create a sorter part way down the above code like below
RowSorter<TableModel> sorter = new TableRowSorter<>(modelR);//creating a new sorter here from my modelR
tableR.setRowSorter(sorter);//set the sorter positon
This allows me to sort on a particular column and order the column.
However the sorter than resets once a refresh takes place:
The refresh process is:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
String stringfromDateR = tffromDateR.getText();
String stringtoDateR = tftoDateR.getText();
if(source == buttonR){
if(timerR != null) {
System.out.print("cancel");
timerR.cancel();
}
// System.out.print("cancel1bbbbb");
timerR = new Timer();
//auto refresh begins
int delayR = 0; //0 seconds startup delay
int periodR = 7000; //x seconds between refreshes
timerR.scheduleAtFixedRate(new TimerTask()
{
public void run() {
try {
getdataR(stringfromDateR,stringtoDateR);
} catch (IOException | BadLocationException ex) {
Logger.getLogger(JavaApplication63.class.getName()).log(Level.SEVERE, null, ex);
}
}
}, delayR, periodR);
}
if(source == buttonR1){
if(timerR != null) {
timerR.cancel();
}
modelR.setRowCount(0);
}
}
and then
private void getdataR(String stringfromDateR,String stringtoDateR) throws IOException, BadLocationException {
StringBuilder retVal = new StringBuilder();
URL oracle = new URL("XXXXXXXXXXXXXXXXXXXXX" );
BufferedReader in = new BufferedReader(new InputStreamReader(oracle.openStream()));
String newLine = "\n";
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
retVal.append(inputLine).append(newLine);
}
in.close();
passStingR(retVal);
}
How can i get the sorter to retain after the refresh has taken place. Im not sure if setting the
modelR.setRowCount(0);
causes the sorter to lose its sorter position.
I did experiment with get sortkeys but this didnt work, i also experimented with
before the refresh happeened
RowSorter<? extends TableModel> tablesorterpos = tableR.getRowSorter();
and then applying
tableR.setRowSorter(tablesorterpos);
after the refresh but this didnt work
This is what i have tried
private void passStingR(StringBuilder retVal) throws BadLocationException {
RowSorter<TableModel> sorter = new TableRowSorter<>(modelR);//creating a new sorter here from my modelR
List<? extends SortKey> sorterR = sorter.getSortKeys();
int scrollPositionR = scrollR.getVerticalScrollBar().getValue();//get value of scroll position stores in javas memory
windowR.remove(scrollR);
tableR.getModel();
modelR.setRowCount(0);
Document docR = null;
try {
docR = loadXMLFromString(retVal.toString());//pull in the XML data into a new doc
} catch (Exception ex) {
Logger.getLogger(remit.class.getName()).log(Level.SEVERE, null, ex);
}
populate1R(docR);
tableR.getTableHeader().setReorderingAllowed(false);//prevent user from changing column order now at refresh level
SimpleDateFormat time_formatterR = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String current_time_strR = time_formatterR.format(System.currentTimeMillis());
updatetFieldR.setText(current_time_strR);
scrollR.remove(tableR);
tableR = new JTable(modelR)
{
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
Font myFont = new Font("Arial",Font.PLAIN,10);
Font myFont1 = new Font("Arial", Font.BOLD,10);
if (!isRowSelected(row)) {
if (tableR.getColumnCount() >= 0) {
String type = (String) getModel().getValueAt(row, 11);
c.setBackground("0.0".equals(type) ? Color.RED : Color.WHITE);
c.setForeground("0.0".equals(type) ? Color.WHITE : Color.BLACK);
c.setFont("0.0".equals(type) ? myFont1: myFont);
}
}
return c;
};
};
TableColumn column = null;
for (int i = 0; i < 18; i++) {
column = tableR.getColumnModel().getColumn(i);
if (i == 0) {
column.setPreferredWidth(70); //sport column is bigger
}
if (i == 1) {
column.setPreferredWidth(500); //sport column is bigger
}
if (i == 7) {
column.setPreferredWidth(30); //sport column is bigger
}
if (i == 8) {
column.setPreferredWidth(20); //sport column is bigger
}
if (i == 9) {
column.setPreferredWidth(25); //sport column is bigger
}
if (i == 14) {
column.setPreferredWidth(500); //sport column is bigger
}
if (i == 15) {
column.setPreferredWidth(10); //sport column is bigger
}
if (i == 16) {
column.setPreferredWidth(20); //sport column is bigger
}
}
tableR.getTableHeader().setReorderingAllowed(false);//prevent the user from sorting the columns at intialise GUI stage even though the user cannnot change this
sorter.setSortKeys(sorterR);
tableR.setRowSorter(sorter);//set the sorter positon
scrollR = new JScrollPane(tableR);
windowR.add(scrollR);
windowR.validate();
scrollR.getVerticalScrollBar().setValue(scrollPositionR);
}
I get this error:
at javax.swing.DefaultRowSorter.rowsDeleted(DefaultRowSorter.java:880)
at javax.swing.JTable.notifySorter(JTable.java:4276)
at javax.swing.JTable.sortedTableChanged(JTable.java:4120)
at javax.swing.JTable.tableChanged(JTable.java:4397)
at javax.swing.table.AbstractTableModel.fireTableChanged(AbstractTableModel.java:296)
at javax.swing.table.AbstractTableModel.fireTableRowsDeleted(AbstractTableModel.java:261)
at javax.swing.table.DefaultTableModel.setNumRows(DefaultTableModel.java:321)
at javax.swing.table.DefaultTableModel.setRowCount(DefaultTableModel.java:339)
at javaapplication63.remit.passStingR(remit.java:238)
at javaapplication63.remit.getdataR(remit.java:227)
at javaapplication63.remit.access$000(remit.java:60)
at javaapplication63.remit$1.run(remit.java:187)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
You can get the current sort keys from the DefaultRowSorter. So the basic logic would be:
getSortKeys()
refresh TableModel
setSortKeys(...)
Edit:
import java.awt.*;
import java.awt.event.*;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
public class TableSortSSCCE extends JPanel
{
private String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
private Object[][] data =
{
{"Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe", "Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black", "Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White", "Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown", "Pool", new Integer(10), new Boolean(false)}
};
private JTable table;
public TableSortSSCCE()
{
super(new BorderLayout());
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model);
table.setPreferredScrollableViewportSize( table.getPreferredSize() );
table.setAutoCreateRowSorter(true);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
JButton clear = new JButton("Clear Table");
clear.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
DefaultTableModel model = (DefaultTableModel)table.getModel();
model.setRowCount(0);
}
});
add(clear, BorderLayout.NORTH);
JButton reload = new JButton("Reload Table");
reload.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
TableRowSorter sorter = (TableRowSorter)table.getRowSorter();
List<? extends RowSorter.SortKey> sortKeys = sorter.getSortKeys();
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table.setModel(model);
table.setAutoCreateRowSorter( true );
sorter = (TableRowSorter)table.getRowSorter();
sorter.setSortKeys( sortKeys );
}
});
add(reload, BorderLayout.SOUTH);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("TableSortSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableSortSSCCE newContentPane = new TableSortSSCCE();
frame.setContentPane(newContentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

JTable Rendering with checkbox

Is there anyone know how I can add a checkbox in this code:
String data[][]={
{"Apple","Banana","Mango"}, {"Apple","Banana","Mango"}, {"Apple","Banana","Mango"}
};
String column[]={"Fruits","Fruits","Fruits"};
table=new JTable(new DefaultTableModel(data, column)){
private Border outside = new MatteBorder(1, 0, 1, 0, Color.RED);
private Border inside = new EmptyBorder(0, 1, 0, 1);
private Border highlight = new CompoundBorder(outside, inside);
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent)c;
// Add a border to the selected row
if (isRowSelected(row))
jc.setBorder( highlight );
return c;
}
};
jScrollPane1.setViewportView(table);
I just want to add checkboxes so that if I check a checkbox it will highlight and all checked checkboxes will be highlighted. Thank You in advance for helping me!
Here is pseudo code, I found somewhere in my repository. Use it according to your use.
import java.awt.Color;
import java.awt.Component;
import javax.swing.*;
import javax.swing.table.*;
public class TableCheckBoxHighLight extends JFrame {
private static final long serialVersionUID = 1L;
private JTable table;
public TableCheckBoxHighLight() {
Object[] columnNames = { "Col1", "Col2", "Select" };
Object[][] data = {
{ "Item1", "123", false },
{ "Item2", "345", false },
{ "Item3", "678", false },
{ "Item4", "901", false }
};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#SuppressWarnings("unchecked")
#Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return String.class;
default:
return Boolean.class;
}
}
#Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int col) {
Component c = super.prepareRenderer(renderer, row, col);
int[] selCols = table.getSelectedColumns();
table.setSelectionBackground(Color.GREEN);
for (int i : selCols)
c.setBackground(Color.RED);
return c;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TableCheckBoxHighLight frame = new TableCheckBoxHighLight();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
});
}
}

Error in getRowCount() on DefaultTableModel

EDIT
I've tried changing the table model back to DefaultTableModel but I am getting an Exception when compiling my code and I can't figure out why!
Here's my table init:
jTable1.setModel(new Table1Model());
jTable1.setDefaultRenderer(Color.class,new ColorRenderer(true));
jTable1.getColumnModel().getColumn(5).setCellEditor(new ColorEditor());
My class extending the model:
class Table1Model extends DefaultTableModel {
//private String[] columnNames = {"Station #",
private Object[] columnNames = {"Station #",
"Name",
"avg Time",
"Buffer",
"Buffer Parts",
"Color"};
private Object[][] data = {
{"1", "Station 1",
new Integer(10), false, new Integer(0), Color.red},
{"2", "Station 2",
new Integer(10), false, new Integer(0), Color.blue},
{"3", "Station 3",
new Integer(10), false, new Integer(0), Color.green},
{"4", "Station 4",
new Integer(10), false, new Integer(0), Color.orange},
{"5", "Station 5",
new Integer(10), false, new Integer(0), Color.black}
};
#Override
public int getColumnCount() {
return columnNames.length;
}
#Override
public int getRowCount() {
//int length = data.length;
//int datalength = Integer.parseInt(length);
return data.length;
}
#Override
public String getColumnName(int col) {
return columnNames[col].toString();
}
#Override
public Object getValueAt(int row, int col) {
return data[row][col];
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
#Override
public Class getColumnClass(int c) {
return getValueAt(0, c).getClass();
}
/*
* Don't need to implement this method unless your table's
* editable.
*/
#Override
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col == 0) { return false; }
else if (col == 4) {
boolean di = (Boolean) getValueAt(row,(col-1));
if (!di) { return false; }
else { return true; }
}
else { return true; }
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
#Override
public void setValueAt(Object value, int row, int col) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
/*public void removeRow(int row) {
data.removeRow(row);
}*/
private void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i=0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j=0; j < numCols; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------");
}
}
This generates the following error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at SimGui$Table1Model.getRowCount(SimGui.java:863)
at javax.swing.table.DefaultTableModel.setDataVector(DefaultTableModel.java:224)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:124)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:106)
at javax.swing.table.DefaultTableModel.<init>(DefaultTableModel.java:86)
at SimGui$Table1Model.<init>(SimGui.java:832)
at SimGui.initComponents(SimGui.java:265)
at SimGui.<init>(SimGui.java:34)
at SimGui$16.run(SimGui.java:789)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:701)
at java.awt.EventQueue.access$000(EventQueue.java:102)
at java.awt.EventQueue$3.run(EventQueue.java:662)
at java.awt.EventQueue$3.run(EventQueue.java:660)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:671)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
Can you help me figure out what's wrong?
Also, will I be able to use the ColorEditor with the DefaultTableModel?
You have two obvious choices here: either give your class a getVectorData() method or else give it another similarly useful method that allows you to extract the nucleus of your data from your model. You probably shouldn't use an AbstractTableModel variable though but rather use a variable of your own custom type that extends AbstractTableModel to allow you to be able to call custom methods of your model.
i.e.,
MyTableModel model = (MyTableModel)jTable1.getModel();
SomeCollection myKeyData = model.getMyKeyData();
Also, this statement:
I have recently created my own class to extend AbstractTableModel to be able to insert some logic on isCellEditable and setValueAt.
Doesn't make sense to me since you could always use a DefaultTableModel and simply override those two methods. But if you use a DefaultTableModel, don't also have it hold the 2D array of object as you're trying to do. Rather feed the data into its internal data via the appropriate constructor or via its addRow(...) method. Else you lose all the power that DefaultTableModel has to offer.
Edit
If you want to use a DefaultTableModel to leverage its methods, then you cannot use a separate data "nucleus" for your model (here your Object[][]), but instead must load your data into the model that is held inside of the DefaultTableModel super class. This can be done either via the correct super constructor or by adding rows of data using its addRow(...) method.
For example, here I load your data into a DefaultTableModel override:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.table.*;
public class TableModelTest extends JPanel {
private static final Object[][] DATA = {
{ "1", "Station 1", new Integer(10), false, new Integer(0), Color.red },
{ "2", "Station 2", new Integer(10), false, new Integer(0), Color.blue },
{ "3", "Station 3", new Integer(10), false, new Integer(0),
Color.green },
{ "4", "Station 4", new Integer(10), false, new Integer(0),
Color.orange },
{ "5", "Station 5", new Integer(10), false, new Integer(0),
Color.black } };
private MyTableModel myTableModel = new MyTableModel(DATA);
private JTable table = new JTable(myTableModel);
public TableModelTest() {
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
table.getColumnModel().getColumn(5)
.setCellRenderer(new ColorCellRenderer());
table.getColumnModel().getColumn(5).setCellEditor(new ColorCellEditor());
}
private static void createAndShowGui() {
TableModelTest mainPanel = new TableModelTest();
JFrame frame = new JFrame("TableModelTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ColorCellEditor extends AbstractCellEditor implements TableCellEditor {
Color currentColor;
JButton button;
JColorChooser colorChooser;
JDialog dialog;
protected static final String EDIT = "edit";
public ColorCellEditor() {
ActionListener actionListener = new MyActionListener();
button = new JButton();
button.setActionCommand(EDIT);
button.addActionListener(actionListener);
button.setBorderPainted(false);
colorChooser = new JColorChooser();
dialog = JColorChooser.createDialog(button, "Pick a Color", true,
colorChooser, actionListener, null);
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (EDIT.equals(e.getActionCommand())) {
button.setBackground(currentColor);
colorChooser.setColor(currentColor);
dialog.setVisible(true);
fireEditingStopped();
} else {
currentColor = colorChooser.getColor();
}
}
}
public Object getCellEditorValue() {
return currentColor;
}
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
currentColor = (Color) value;
return button;
}
}
class ColorCellRenderer implements TableCellRenderer {
private static final int IMG_WIDTH = 70;
private static final int IMG_HEIGHT = 20;
private JLabel label = new JLabel();
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean arg2, boolean arg3, int arg4, int arg5) {
Color color = (Color) value;
BufferedImage img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics();
g.setColor(color);
g.fillRect(0, 0, IMG_WIDTH, IMG_HEIGHT);
g.dispose();
ImageIcon icon = new ImageIcon(img);
label.setIcon(icon);
return label;
}
}
class MyTableModel extends DefaultTableModel {
private static final String[] COLUMN_NAMES = { "Station #", "Name",
"avg Time", "Buffer", "Buffer Parts", "Color" };
public MyTableModel(Object[][] data) {
super(data, COLUMN_NAMES);
}
#Override
public boolean isCellEditable(int row, int col) {
if (col == 0) {
return false;
} else if (col == 4) {
boolean di = (Boolean) getValueAt(row, (col - 1));
if (!di) {
return false;
} else {
return true;
}
} else {
return true;
}
}
public void printDebugData() {
int numRows = getRowCount();
int numCols = getColumnCount();
for (int i = 0; i < numRows; i++) {
System.out.print(" row " + i + ":");
for (int j = 0; j < numCols; j++) {
Object datum = getValueAt(i, j);
// System.out.print(" " + data[i][j]);
System.out.print(" " + datum);
}
System.out.println();
}
System.out.println("--------------------------");
}
}

custom cell renderer for particular row and column

puuuuuuf, I'm starting to like swing :) I'm trying to write a cellRenderer to customy render all cells besides those which in first row and column. So I wrote the following:
public class CustomTableCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
Component cell = super.getTableCellRendererComponent(table, obj, isSelected, hasFocus, row, column);
if(row >0&&column>0){
cell.setBackground(Color.GREEN);
}
return cell;
}
}
and set the renderer as following:
scheduleTable.setDefaultRenderer(Object.class, new CustomTableCellRenderer());
but for some reason such an approach applies renderer to all the cell. So all of them are Green. If I'm doing something wrong, could you help me with that please?
Thanks in advance!
ADDITION
scheduleTable = new JTable() {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
int modelRow = convertRowIndexToModel(row);
int modelColumn = convertColumnIndexToModel(column);
if (modelColumn != 0 && modelRow != 0) {
comp.setBackground(Color.GREEN);
}
return comp;
}
};
this code makes all the table green as well.
This code:
scheduleTable = new JTable(tableModel) {
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
int modelRow = convertRowIndexToModel(row);
int modelColumn = convertColumnIndexToModel(column);
if (modelRow != 0 && modelColumn != 0) {
setBackground(Color.GREEN);
} else {
setBackground(Color.WHITE);
}
return comp;
}
};
gives me the following result ;(
The following situations I have with differents n in expression row != 0 && column != 0:
you can use prepareRenderer, is easiest and more confortable that XxxCellRenderer
great code example is Table Row Rendering by #camickr
EDIT:
if (modelColumn != 0 || modelRow != 0) {
and with if (modelColumn != 0 && modelRow != 0) {
from code
import java.awt.*;
import java.awt.font.TextAttribute;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.*;
public class TablePrepareRenderer extends JFrame {
private static final long serialVersionUID = 1L;
private JTable table;
public TablePrepareRenderer() {
Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"};
Object[][] data = {
{"Buy", "IBM", new Integer(1000), new Double(80.50), false},
{"Sell", "MicroSoft", new Integer(2000), new Double(6.25), true},
{"Sell", "Apple", new Integer(3000), new Double(7.35), true},
{"Buy", "Nortel", new Integer(4000), new Double(20.00), false}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
table = new JTable(model) {
private static final long serialVersionUID = 1L;
private Border outside = new MatteBorder(1, 0, 1, 0, Color.red);
private Border inside = new EmptyBorder(0, 1, 0, 1);
private Border highlight = new CompoundBorder(outside, inside);
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
int modelRow = convertRowIndexToModel(row);
int modelColumn = convertColumnIndexToModel(column);
if (!isRowSelected(modelRow)) {
if (modelColumn != 0 || modelRow != 0) {
comp.setBackground(Color.GREEN);
} else {
comp.setBackground(table.getBackground());
}
}
return comp;
/*Component comp = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) comp;
Map attributes = (new Font("Serif", Font.PLAIN, 12)).getAttributes();
//attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
if (!isRowSelected(row)) {
comp.setForeground(Color.black);
comp.setBackground(row % 2 == 0 ? Color.white : Color.orange);
int modelRow = convertRowIndexToModel(row);
String type = (String) getModel().getValueAt(modelRow, 0);
if (type.equals("Sell")) {
comp.setFont(new Font(attributes));
comp.setForeground(Color.red);
} else {
comp.setFont(new Font("Serif", Font.BOLD, 12));
}
} else {
comp.setFont(table.getFont());
}
jc.setBorder(BorderFactory.createCompoundBorder(jc.getBorder(), BorderFactory.createEmptyBorder(0, 0, 0, 5)));
return comp;*/
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TablePrepareRenderer frame = new TablePrepareRenderer();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Use the row and column value without converting into model

Custom TableCellRenderer ignored by Look&Feel

I have a JTable for which I have provided a custom TableCellRenderer that colors numeric cells in red/gray/green depending on their value (<0, 0, >0).
However, when I use the Nimbus L&F, the label.setForeground() method is ignored: when calling label.getForeground() I can see that the number has the right color, for example red, but on the screen it comes black. If I remove the L&F it works fine.
Is there a way to gently ask the L&F to accept using my color for that cell?
ps: I know that the javadoc of setForeground() is clear about the fact that the L&F might ignore the call, so I'm looking for a workaround.
think are complicated by using JLabel,
if you'll use Components then there no needed to override NimbusDefaults or Painter,
sorry I have no ideas to playing with Nimbus & NimbusDefaults & Renderer, because I have another favorite L&F please read some more info about Look and Feels
(without override NimbusDefaults from JCheckBox, this issue are solved a few times on this forum)
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class TablePrepareRenderer extends JFrame {
private static final long serialVersionUID = 1L;
private JTable table;
public TablePrepareRenderer() {
Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"};
Object[][] data = {
{"Buy", "IBM", new Integer(1000), new Double(80.50), false},
{"Sell", "MicroSoft", new Integer(2000), new Double(6.25), true},
{"Sell", "Apple", new Integer(3000), new Double(7.35), true},
{"Buy", "Nortel", new Integer(4000), new Double(20.00), false}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
private static final long serialVersionUID = 1L;
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
/*#Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return String.class;
case 2:
return Integer.class;
case 3:
return Double.class;
default:
return Boolean.class;
}
}*/
};
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
int firstRow = 0;
int lastRow = table.getRowCount() - 1;
if (row == lastRow) {
((JComponent) c).setBackground(Color.red);
} else if (row == firstRow) {
((JComponent) c).setBackground(Color.blue);
} else {
((JComponent) c).setBackground(table.getBackground());
}
return c;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane);
}
/*private static String[] suffix = new String[]{"", "k", "m", "b", "t"};
private static int MAX_LENGTH = 4;
private static String format(double number) {
String r = new DecimalFormat("##0E0").format(number);
r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);
return r.length() > MAX_LENGTH ? r.replaceAll("\\.[0-9]+", "") : r;
}*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception fail) {
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TablePrepareRenderer frame = new TablePrepareRenderer();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
/*long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 99999900};
for (long number : numbers) {
System.out.println(number + " = " + format(number));
}*/
}
}
Ok, thanks to mKorbel's answer, I realised that I was using ColorUIResource instead of Color. In other words:
label.setForeground(Color.red); //works
label.setForeground(new ColorUIResource(Color.red)); //doesn't work
I'm not sure I understand why one works and not the other (Color is the direct superclass of ColorUIResource), but problem solved.

Categories