Drawing Swing JTable rows with different colors using TableCellRenderer interface Example

In this example we are going to demonstrate how to use Java Swing TableCellRenderer interface to customize cell rendering. When a JTable object is created, several default renderers are also created. Those renderers are capable of rendering Boolean choices, dates, image icons, numbers, and objects (as strings). If you do not explicitly attach a custom render to a column, a table component chooses a default renderer on your behalf. However, If you discover that a table component’s default renderers do not meet your needs. At that time, you will want to develop a custom renderer via an implementation of TableCellRenderer. So, we will show TableCellRenderer implementation in a real business case.

Let’s suppose that we need to create an application which monitor the stock market shares prices, it shows which share goes down and up. So, we need to show these share attributes (SymbolCompany Name,PriceChange% ChangeVolume). In addition, we also need to color each share price Change and % Change in Green when it goes up and in Red when it goes down.

To accomplish that task, we should do two things. First, we create a class that implements the TableCellRenderer interface and overrides that interface’s getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) method to return a Component reference to an object that performs the actual rendering. Second, we create an object from your class and call JTable’s setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) method to establish that object as a cell renderer.

1. Custom Table Cell Renderer

We create PriceChangeColorRenderer.java class to play as a custom price cell renderer where it renders the Change and % Change cells text color using setForeground(Color c) based on the Change cell value, if it’s greater than zero, the color will be Green. However, if it’s less than zero, the color will be Red.

Also, we apply the zebra style on the JTable rows using setBackground(Color c) as the following:

1

2

3

4

5

6

// Apply zebra style on table rows

if (row % 2 == 0) {

    c.setBackground(Constants.EVEN_ROW_COLOR);

} else {

    c.setBackground(Constants.ODD_ROW_COLOR);

}

PriceChangeColorRenderer.java

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

package com.jcg;

import java.awt.Color;

import java.awt.Component;

import javax.swing.JTable;

import javax.swing.table.DefaultTableCellRenderer;

import javax.swing.table.TableCellRenderer;

/**

 * @author ashraf_sarhan

 *

 */

public class PriceChangeColorRenderer implements TableCellRenderer {

    public static final DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();

    @Override

    public Component getTableCellRendererComponent(JTable table, Object value,

            boolean isSelected, boolean hasFocus, int row, int column) {

        Component c = DEFAULT_RENDERER.getTableCellRendererComponent(table,

                value, isSelected, hasFocus, row, column);

        // Apply zebra style on table rows

        if (row % 2 == 0) {

            c.setBackground(Constants.EVEN_ROW_COLOR);

        } else {

            c.setBackground(Constants.ODD_ROW_COLOR);

        }

        if (column == Constants.CHANGE_IDX

                || column == Constants.PERCENTAGE_CHANGE_IDX) {

            Object priceChangeObj = table.getModel().getValueAt(row,

                    Constants.CHANGE_IDX);

            double priceChange = Double.parseDouble(priceChangeObj.toString());

            Color color;

            if (priceChange > 0) {

                color = Constants.PRICE_UP_COLOR;

            } else {

                color = Constants.PRICE_DOWN_COLOR;

            }

            c.setForeground(color);

        } else {

            c.setForeground(Constants.DEFAULT_FOREGROUND_COLOR);

        }

        return c;

    }

}

2. Stock Market Price Data Simulator

We create TableDataFeeder.java class to simulate the stock market prices live feed with only ten stocks and load it into the Stocks Market Data table. Also, we simulate the price changes by selecting a random stock then decrease or increase its price by a random price delta on every call for the feedData(JTable table).

ADVERTISEMENT

TableDataFeeder.java

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

package com.jcg;

import java.math.BigDecimal;

import java.math.RoundingMode;

import java.util.concurrent.ThreadLocalRandom;

import javax.swing.JTable;

import javax.swing.table.DefaultTableModel;

/**

 * @author ashraf_sarhan

 *

 */

public class TableDataFeeder {

    private static boolean isPriceUp = true;

    public static void feedData(JTable table) {

        // Get a random index to apply the price update

        int randomRowIdx = ThreadLocalRandom.current().nextInt(0, 10);

        updatePrice(table, randomRowIdx);

    }

    private static void updatePrice(JTable table, int row) {

        DefaultTableModel model = (DefaultTableModel) table.getModel();

        Double oldPrice = (Double) model.getValueAt(row, Constants.PRICE_IDX);

        Double newPrice = 0.0;

        Double priceChange = 0.0;

        Double priceChangePercentage = 0.0;

        String priceChangePercentageStr = "";

        Double priceDelta = ThreadLocalRandom.current().nextDouble(

                Constants.PRICE_CHANGE_RANGE[0],

                Constants.PRICE_CHANGE_RANGE[1]);

        if (isPriceUp) {

            // Get a newer bigger price value

            newPrice = oldPrice + priceDelta;

            isPriceUp = false;

        } else {

            // Get a newer smaller price value

            newPrice = oldPrice - priceDelta;

            isPriceUp = true;

        }

        if (newPrice > 0.0) {

            priceChange = newPrice - oldPrice;

            priceChangePercentage = roundDouble(new Double(

                    (newPrice / oldPrice - 1) * 100), Constants.ROUND_PLACES);

            if (priceChangePercentage > 0) {

                priceChangePercentageStr = Constants.PLUS_SIGN

                        + priceChangePercentage.toString()

                        + Constants.PERCENTAGE_SIGN;

            } else {

                priceChangePercentageStr = priceChangePercentage.toString()

                        + Constants.PERCENTAGE_SIGN;

            }

            // Update table row with the new values

            model.setValueAt(roundDouble(newPrice, Constants.ROUND_PLACES),

                    row, Constants.PRICE_IDX);

            model.setValueAt(roundDouble(priceChange, Constants.ROUND_PLACES),

                    row, Constants.CHANGE_IDX);

            model.setValueAt(priceChangePercentageStr, row,

                    Constants.PERCENTAGE_CHANGE_IDX);

        }

    }

    private static Double roundDouble(double value, int places) {

        if (places < 0)

            throw new IllegalArgumentException();

        BigDecimal bd = new BigDecimal(value);

        bd = bd.setScale(places, RoundingMode.HALF_UP);

        return bd.doubleValue();

    }

}

Also, we have a supplementary class Constants.java which contains our constants.

Constants.java

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

package com.jcg;

import java.awt.Color;

/**

 * @author ashraf_sarhan

 *

 */

public class Constants {

    public static final Object[] TABLE_HEADER = { "Symbol", "Company Name",

            "Price", "Change", "% Change", "Volume" };

    public static final Object[][] DATA = {

            { "BAC", "Bank of America Corporation", 15.98, 0.14, "+0.88%",

                    32157250 },

            { "AAPL", "Apple Inc.", 126.57, -1.97, "-1.54%", 31367143 },

            { "ABBV", "AbbVie Inc.", 57.84, -2.43, "-4.03%", 30620258 },

            { "ECA", "Encana Corporation", 11.74, -0.53, "-4.33%", 27317436 },

            { "VALE", "Vale S.A.", 6.55, -0.33, "-4.80%", 19764400 },

            { "FB", "Facebook, Inc.", 81.53, 0.64, "+0.78%", 16909729 },

            { "PBR", "Petróleo Brasileiro S.A. - Petrobras", 6.05, -0.12,

                    "-2.02%", 16181759 },

            { "NOK", "Nokia Corporation", 8.06, 0.01, "+0.12%", 13611860 },

            { "PCYC", "Pharmacyclics Inc.", 254.67, 24.19, "+10.50%", 13737834 },

            { "RAD", "Rite Aid Corporation", 7.87, -0.18, "-2.24%", 13606253 } };

    public static final int DATA_REFRESH_RATE = 3000;

    public static final Color PRICE_UP_COLOR = Color.GREEN;

    public static final Color PRICE_DOWN_COLOR = Color.RED;

    public static final Color DEFAULT_FOREGROUND_COLOR = Color.BLACK;

    public static final Color ODD_ROW_COLOR = Color.decode("#F8F8F8");

    public static final Color EVEN_ROW_COLOR = Color.WHITE;

    public static final String PLUS_SIGN = "+";

    public static final String PERCENTAGE_SIGN = "%";

    public static final int ROUND_PLACES = 2;

    public static final double[] PRICE_CHANGE_RANGE = { 0.1, 0.5 };

    public static final int PRICE_IDX = 2;

    public static final int CHANGE_IDX = 3;

    public static final int PERCENTAGE_CHANGE_IDX = 4;

}

3. Test Table Cell Renderer

We create TableCellRendererDemo.java class to test our example where we instantiate a table object of JTable class and another new object colorRenderer of PriceChangeColorRenderer class, then we call setDefaultRenderer(Class<?> columnClass, TableCellRenderer renderer) on the table object to play as table cell renderer.

TableCellRendererDemo.java

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

package com.jcg;

import java.awt.Dimension;

import javax.swing.BorderFactory;

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.JScrollPane;

import javax.swing.JTable;

import javax.swing.SwingUtilities;

import javax.swing.border.TitledBorder;

import javax.swing.table.DefaultTableModel;

/**

 * @author ashraf_sarhan

 *

 */

@SuppressWarnings("serial")

public class TableCellRendererDemo extends JPanel {

    private static JTable table;

    public TableCellRendererDemo() {

        DefaultTableModel model = new DefaultTableModel(Constants.DATA,

                Constants.TABLE_HEADER);

        table = new JTable(model);

        // Set custom price color renderer

        PriceChangeColorRenderer colorRenderer = new PriceChangeColorRenderer();

        table.setDefaultRenderer(Object.class, colorRenderer);

        JScrollPane scrollpane = new JScrollPane(table);

        scrollpane.setPreferredSize(new Dimension(700, 182));

        scrollpane.setViewportView(table);

        JPanel panel = new JPanel();

        panel.setBorder(BorderFactory.createTitledBorder(

                BorderFactory.createEtchedBorder(), "Market Movers",

                TitledBorder.CENTER, TitledBorder.TOP));

        panel.add(scrollpane);

        add(panel);

    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                try {

                    createAndShowGUI();

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        });

        new Thread(new Runnable() {

            public void run() {

                while (true) {

                    try {

                        SwingUtilities.invokeLater(new Runnable() {

                            public void run() {

                                TableDataFeeder.feedData(table);

                            }

                        });

                        Thread.sleep(Constants.DATA_REFRESH_RATE);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        }).start();

    }

    public static void createAndShowGUI() throws Exception {

        JFrame frame = new JFrame("Stocks Market Data");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(new TableCellRendererDemo());

        frame.pack();

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }

}

Output:

stocks-market-data

Figure 1: Stocks Market Data

4. Download the Eclipse Project

This was an example on how to draw Swing JTable rows with different colors using TableCellRenderer interface.

Download
You can download the full source code of this example here: TableCellRendererExampleCode.zip

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值