5

I have a JTable where one column displays values in the following format:

423545(50),[7568787(50)],53654656,2021947(50),[021947],2021947(50),[8021947(50)]

I am wondering if it is possible to display the values within square brackets in RED?

I have been googling around for the last few days and have found several examples showing how to set the 'background' of a cell but not really how to change the font of a cell especially not a specific part of the text.

public class myTableCellRenderer
       extends DefaultTableCellRenderer {
  public Component getTableCellRendererComponent(JTable table,
                                                 Object value,
                                                 boolean isSelected,
                                                 boolean hasFocus,
                                                 int row,
                                                 int column) {
    Component c = 
      super.getTableCellRendererComponent(table, value,
                                          isSelected, hasFocus,
                                          row, column);

    if (column == 3) {
       c.setForeground(Color.YELLOW);
       c.setBackground(Color.RED);
    }
    return c;
  }

Is it really possible to change part of the text to be a different color (i.e. the text that is within the square brackets).

Edit

The text i showed as an example is the actual text shown in the table cell (the comma separators are not representing columns). The text displayed in the cell is a comma separated string that i display on the table in column 3.

As an example the table could look like this

product_id |product_name| invoice_numbers
12         |    Books   | 423545(50),[7568787(50)],53654656,2021947(50),[021947],2021947(50),[8021947(50)]
323        |    Videos  | 423545(50),[7568787(50)],53654656,2021947(50),[021947],2021947(50),[8021947(50)]
4434       |    Music   | 423545(50),[7568787(50)],53654656,2021947(50),[021947],2021947(50),[8021947(50)]
ziggy
  • 15,677
  • 67
  • 194
  • 287

4 Answers4

5

You must use a Cell renderer combined with HTML.

Here is a small demo example:

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class TestTable2 {

    class MyCellRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (value instanceof String) {
                String string = (String) value;
                if (string.indexOf('[') > -1) {
                    setText(getHTML(string));
                }
            }
            return tableCellRendererComponent;
        }

        private String getHTML(String string) {
            StringBuilder sb = new StringBuilder();
            sb.append("<html>");
            int index = 0;
            while (index < string.length()) {
                int next = string.indexOf('[', index);
                if (next > -1) {
                    int end = string.indexOf(']', next);
                    if (end > -1) {
                        next++;
                        sb.append(string.substring(index, next));
                        sb.append("<span style=\"color: red;\">");
                        sb.append(string.substring(next, end));
                        sb.append("</span>");
                        index = end;
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
            sb.append(string.substring(index, string.length()));
            sb.append("</html>");
            return sb.toString();
        }
    }

    protected void initUI() {
        DefaultTableModel model = new DefaultTableModel();
        for (int i = 0; i < 2; i++) {
            model.addColumn("Col-" + (i + 1));
        }
        for (int i = 0; i < 200; i++) {
            Vector<Object> row = new Vector<Object>();
            for (int j = 0; j < 5; j++) {
                row.add("423545(50),[7568787(50)],53654656,2021947(50),[021947],2021947(50),[8021947(50)]");
            }
            model.addRow(row);
        }
        JTable table = new JTable(model);
        table.setDefaultRenderer(Object.class, new MyCellRenderer());
        JFrame frame = new JFrame(TestTable2.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JScrollPane scrollpane = new JScrollPane(table);
        frame.add(scrollpane, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestTable2().initUI();
            }
        });
    }

}

And the result:

Result

Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
2

This is what you are looking for Cell render

How to proceed:

  1. get the default cell render component using getTableCellRendererComponent() function with the appropriate parameters.

  2. parse the text of the cell and apply your formatting using setForeground() function.

Arpit
  • 12,767
  • 3
  • 27
  • 40
2
Is it really possible to change part of the text to be a different color

yes is possible, for

  • simple highlighter is possible with JTextField/JTextArea as Renderers component

  • multiple of the Highlighter have to look for JTextPane as Renderers component

  • (easier of ways) you can to formatting cell by using Html (todays Java up to Html3.2)

mKorbel
  • 109,525
  • 20
  • 134
  • 319
0

Yes It is possible.
EDIT
First you need to create a subclass of DefaultTableCellRenderer where you override getTableCellRendererComponent method to render the desired column according to your need. And then change the renderer for that column by the subclass of DefaultTableCellRenderer.
Here is the example to achieve this task:

import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
public class TableExample extends JFrame
{
    JTable myTable ;
    Object[][] data= {
                    {"34","[56],987,[(56)]"},
                    {"5098","345,([{78}])"},
                    {"567","4312"}
                };
    Object[] col = {"First","Second"};
    public TableExample()
    {
        super("CellRendererExample");
    }
    public void prepareAndShowGUI()
    {
        myTable = new JTable(data,col);
        myTable.getColumnModel().getColumn(1).setCellRenderer(new MyTableCellRenderer());
        JScrollPane jsp = new JScrollPane(myTable);
        getContentPane().add(jsp);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
    public class MyTableCellRenderer extends DefaultTableCellRenderer 
    {
        public Component getTableCellRendererComponent(JTable table,Object oValue, boolean isSelected, boolean hasFocus, int row, int column) 
        {
            Component c = super.getTableCellRendererComponent(table, oValue,isSelected, hasFocus,row, column);
            String value = (String)oValue;
            StringBuilder sBuilder = new StringBuilder();
            sBuilder.append("<HTML><BODY>");
            StringTokenizer tokenizer = new StringTokenizer(value,",");
            while (tokenizer.hasMoreTokens())
            {
                String token = tokenizer.nextToken();
                int index = token.indexOf("[");
                if (index != -1)
                {
                    sBuilder.append(token.substring(0,index));
                    int lastIndex = token.lastIndexOf(']');
                    String subValue = token.substring(index + 1,lastIndex);
                    sBuilder.append("[<FONT color = red>"+subValue+"</FONT>]");
                    if (lastIndex < token.length() -1)
                    {
                        sBuilder.append(token.substring(lastIndex+1,token.length()));
                    }
                    sBuilder.append(",");
                }
                else
                {
                    sBuilder.append(token+",");
                }
            }
            if (sBuilder.lastIndexOf(",") == sBuilder.length() - 1)
            {
                sBuilder.deleteCharAt(sBuilder.length() - 1 );
            }
            sBuilder.append("</BODY></HTML>");
            value = sBuilder.toString(); ;
            JLabel label =(JLabel)c;
            label.setText(value);
            return label;
        }
    }
    public static void main(String st[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                TableExample tae = new TableExample();
                tae.prepareAndShowGUI();
            }
        });
    }

}
Vishal K
  • 12,976
  • 2
  • 27
  • 38
  • Will this not change the font for all the text in that specific cell? It does check that the text contains the characters [ and ] but wouldn't c.setForeground set the foreground for everything within that cell? – ziggy Jan 27 '13 at 12:02
  • -1 You should use an appropriate TableCellRenderer. and also -1 because it will set everything in red, not just the value between brackets – Guillaume Polet Jan 27 '13 at 12:03
  • @ziggy My Mistake . I misunderstood your Question. See my Edit. – Vishal K Jan 27 '13 at 13:55
  • @kleopatra May i know which naming convention did i miss?? – Vishal K Jan 27 '13 at 13:58
  • `myTableCellRenderer ` should be `MyTableCellRenderer`: notice the capital "M" at the beginning. Also, you should not override `getCellRenderer` but actually access `setDefaultRenderer` or `table.getColumnModel().getColumn(1).setCellRenderer(cellRenderer)`. Overriding methods must be used when you add functionality. – Guillaume Polet Jan 27 '13 at 14:05
  • Rather use `StringBuilder` than `StringBuffer`. Using string concatenation ('+') when you have already a StringBuilder/StringBuffer is counterproductive, always use `append()`. Your parsing code is incorrect since you call `value = value + " – Guillaume Polet Jan 27 '13 at 14:10
  • @GuillaumePolet: Thanks for the notable points. There were more to watch in previous code. It is updated now.. – Vishal K Jan 27 '13 at 14:54