Search code examples
javaswingenumsjlistlistcellrenderer

How to set different text color according to an enum in JList?


EDIT : Here is the code updated after @HovercraftFullOfEels answer :

note : I didn't use the HashMap, because I wanted to do several actions, like changing color and making the font bold or italic, and the HashMap provided in the answer only worked to set a specific color to a specific enum type.

so, here is the code :

package src;

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;

import src.MainWindow.LogType;

public class MainWindow {

    public enum LogType {
        ERROR("Error"), COMMENT("Comment"), READ_INFO("Read_Info"), ACTION(
                "Action"), PARAM_ERROR("Param_Error");
        String text;

        private LogType(String s) {
            this.text = s;
        }

        public void setText(String s) {
            this.text = s;
        }

        public String getText() {
            return text;
        }
    };

    private JFrame frmNavdng;
    private static DefaultListModel<LogType> logListModel = new DefaultListModel<>();
    private static JList<LogType> log_List = new JList<>(logListModel);

    public MainWindow() {
        initialize();
    }

    public static void add_Log_Line(LogType type, String s) {
        // add action to the log list
        type.setText(s);
        logListModel.addElement(type);
        log_List.ensureIndexIsVisible(log_List.getLastVisibleIndex());
    }

    private void initialize() {
        /** Frame Initialisation */
        frmNavdng = new JFrame();
        frmNavdng.setFont(new Font("Tahoma", Font.PLAIN, 12));
        frmNavdng.setTitle("list_window");
        frmNavdng.setResizable(false);
        frmNavdng.setBounds(100, 100, 640, 400);
        frmNavdng.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmNavdng.getContentPane().setLayout(null);

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setBounds(0, 0, frmNavdng.getWidth(), frmNavdng.getHeight());
        frmNavdng.getContentPane().add(scrollPane);
        scrollPane.setViewportView(log_List);
        log_List.setToolTipText("history of the last actions");
        log_List.setVisibleRowCount(10);
        log_List.setValueIsAdjusting(true);
        log_List.setFont(new Font("Tahoma", Font.PLAIN, 10));
        log_List.setCellRenderer(new MyCellRenderer());
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    MainWindow window = new MainWindow();
                    window.frmNavdng.setVisible(true);
                    for (int i = 0; i <= 5; i++) {
                        add_Log_Line(LogType.ACTION, ("loop " + i));
                    }
                } catch (Exception e) {
                    e.toString();
                }
            }
        });
    }

}

class MyCellRenderer extends DefaultListCellRenderer {

    private static final long serialVersionUID = 1L;

    public MyCellRenderer() {
        setOpaque(true);
    }

    @Override
    public Component getListCellRendererComponent(JList<?> list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {
        LogType lt = (LogType) value;   

        value = lt.getText();

        Color background = Color.white;
        Color foreground = Color.black;
        Font font = list.getFont();

        if (lt == LogType.ACTION) {
            foreground = Color.blue;
        }

        if (lt == LogType.COMMENT) {
            foreground = Color.darkGray;
        }

        if (lt == LogType.ERROR) {
            foreground = Color.red;
            font = new Font(list.getFont().getFontName(), Font.BOLD, list
                .getFont().getSize());
        }

        if (lt == LogType.READ_INFO) {
            foreground = Color.magenta;
            font = new Font(list.getFont().getFontName(), Font.ITALIC, list.getFont().getSize());
        }

        if (lt == LogType.PARAM_ERROR) {
            foreground = Color.orange;
            font = new Font(list.getFont().getFontName(), Font.BOLD, list
                .getFont().getSize());
        }

        if (isSelected)
            background = Color.lightGray;

        Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);

        c.setForeground(foreground);
        c.setBackground(background);
        c.setFont(font);

        return c;
    }
}

EDIT 2 : Here is an illustration of what I get and what I would like to get :

If I run the code given by @HovercraftFullofEels, slightly modified to change the text :

for(int i = 0; i<= 10; i++)
{
    LogType logType = LogType.values()[i];
    //just added this line
    logType.setText("Type : " + logType.toString() + " - Loop : " + i);
    logListModel.addElement(logType);
}

I get this result : what I get by running the code each type of log get the last text given for each one... and it'd be great if they could get the text I gave them in the beginning so that after I could display text like "Failed to open the file" with the ERROR type and style, "The parameter given in this file is wrong, it will be ignored" with the READ_INFO style and type, and the "result written in the file result.txt" as an ACTION, for example.

With the code given, I don't get how and where I could set this text and make it to be "static" (meaning it won't change here).

--------- OLD QUESTION ---------

I am using a JList as a log viewer, and I'd like to have some lines added in different color. For example, I have an enum with the types COMMENT, ACTION and ERROR. COMMENT will be in darkgrey, ACTION in blue and ERROR in red.

I tried to make a custom ListCellRendered, but I can't figure out how to set the different color according to the enum.

Here is my code :

public class MainWindow {
/* all the other declarations... */
private static JList<String> log_List;

/* configuration of the list somewhere in the code */
log_List = new JList<String>(new DefaultListModel<String>());
scrollPane.setViewportView(log_List);
log_List.setToolTipText("history of the last actions");
log_List.setVisibleRowCount(10);
log_List.setValueIsAdjusting(true);
log_List.setCellRenderer(new MyCellRenderer());

public enum LOG_TYPE {
    ERROR, COMMENT, READ_INFO, ACTION
};

// add action to the log list
public static void add_Log_Line(LOG_TYPE type, String s) {
//what I did before, but not working... 
/* if (type == LOG_TYPE.ERROR)  log_List.setForeground(Color.red);
    if (type == LOG_TYPE.ACTION) log_List.setForeground(Color.blue);
    if (type == LOG_TYPE.COMMENT) log_List.setForeground(Color.darkGray);
    if (type == LOG_TYPE.READ_INFO)log_List.setForeground(Color.magenta); */

    ((DefaultListModel<String>) log_List.getModel()).addElement(s);
    //makes the last raw visible after adding a line
    log_List.ensureIndexIsVisible(log_List.getLastVisibleIndex());
}

/* somewhere else in the code */
//add the path of a file chosen in a JFileChooser (fc)
add_Log_Line(LOG_TYPE.ACTION, "OPEN - " + fc.getSelectedFile().getAbsolutePath());


/* My custom cell renderer */
class MyCellRenderer extends JLabel implements ListCellRenderer<Object> {
public MyCellRenderer() {
    setOpaque(true);
}

public Component getListCellRendererComponent(JList<?> list, Object value,
        int index, boolean isSelected, boolean cellHasFocus) {

    setText(value.toString());

    Color background = Color.white;
    Color foreground = Color.black;

    if (value == LOG_TYPE.ACTION)
        foreground = Color.blue;
    if (value == LOG_TYPE.COMMENT)
        foreground = Color.darkGray;
    if (value == LOG_TYPE.ERROR)
        foreground = Color.red;
    if (value == LOG_TYPE.READ_INFO)
        foreground = Color.magenta;

    setForeground(foreground);
    setBackground(background);

    return this;
}

}

all I get is a black on white colored list...


Solution

  • I doubt you want to really add log types to the JList. I added a class called LogEntry and updated the code. See whether it helps.

    package src;
    
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.awt.Font;
    
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.DefaultListModel;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JScrollPane;
    
    import com.sun.javafx.css.converters.FontConverter.FontStyleConverter;
    
    import src.MainWindow.LogEntry;
    import src.MainWindow.LogType;
    
    public class MainWindow {
    
        public enum LogType {
            // @formatter:off
            ERROR("Error", Color.RED, Font.BOLD),
            COMMENT("Comment", Color.BLUE, Font.ITALIC),
            READ_INFO("Read_Info", Color.BLACK, 0),
            ACTION("Action", Color.YELLOW, 0),
            PARAM_ERROR("Param_Error", Color.RED, Font.ITALIC | Font.BOLD);
            // @formatter:on
    
            String text;
            Color color;
            int fontStyle;
    
            private LogType(String s, Color color, int fontStyle) {
                this.text = s;
                this.color = color;
                this.fontStyle = fontStyle;
            }
    
            public void setText(String s) {
                this.text = s;
            }
    
            public String getText() {
                return text;
            }
    
            public int getFontStyle() {
                return fontStyle;
            }
    
            public Color getColor() {
                return color;
            }
        };
    
        public static class LogEntry {
            private LogType type;
            private String text;
    
            public LogEntry(LogType type, String text) {
                this.type = type;
                this.text = text;
            }
    
            public LogType getType() {
                return type;
            }
    
            public String getText() {
                return text;
            }
        }
    
        private JFrame frmNavdng;
        private static DefaultListModel<LogEntry> logListModel = new DefaultListModel<>();
        private static JList<LogEntry> log_List = new JList<>(logListModel);
    
        public MainWindow() {
            initialize();
        }
    
        public static void add_Log_Line(LogType type, String s) {
            // add action to the log list
            type.setText(s);
            logListModel.addElement(new LogEntry(type, s));
            log_List.ensureIndexIsVisible(log_List.getLastVisibleIndex());
        }
    
        private void initialize() {
            /** Frame Initialisation */
            frmNavdng = new JFrame();
            frmNavdng.setFont(new Font("Tahoma", Font.PLAIN, 12));
            frmNavdng.setTitle("list_window");
            frmNavdng.setResizable(false);
            frmNavdng.setBounds(100, 100, 640, 400);
            frmNavdng.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frmNavdng.getContentPane().setLayout(null);
    
            JScrollPane scrollPane = new JScrollPane();
            scrollPane.setBounds(0, 0, frmNavdng.getWidth(), frmNavdng.getHeight());
            frmNavdng.getContentPane().add(scrollPane);
            scrollPane.setViewportView(log_List);
            log_List.setToolTipText("history of the last actions");
            log_List.setVisibleRowCount(10);
            log_List.setValueIsAdjusting(true);
            log_List.setFont(new Font("Tahoma", Font.PLAIN, 10));
            log_List.setCellRenderer(new MyCellRenderer());
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    try {
                        MainWindow window = new MainWindow();
                        window.frmNavdng.setVisible(true);
                        LogType[] values = LogType.values();
                        for (LogType logType : values) {
                            add_Log_Line(logType, "This is log type " + logType.getText());
                        }
                    } catch (Exception e) {
                        e.toString();
                    }
                }
            });
        }
    
    }
    
    class MyCellRenderer extends DefaultListCellRenderer {
    
        private static final long serialVersionUID = 1L;
    
        public MyCellRenderer() {
            setOpaque(true);
        }
    
        @Override public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            LogEntry entry = (LogEntry) value;
    
            value = entry.getText();
    
            Color background = Color.white;
            Color foreground = entry.getType().getColor();
    
            Font font = list.getFont();
    
            font = new Font(list.getFont().getFontName(), entry.getType().getFontStyle(), list.getFont().getSize());
    
            if (isSelected)
                background = Color.lightGray;
    
            Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    
            c.setForeground(foreground);
            c.setBackground(background);
            c.setFont(font);
    
            return c;
        }
    }