Changing JList row color at runtime

独自空忆成欢 提交于 2019-11-29 02:32:14

Based on ListDemo sample from SUN.

If you enter some text in the textfield which isn't in the list and you hit highlight it gets added.

If the text is in the list and you hit highlight the entry in the list gets temporarily highlighted blue.

Note the solution here with the match field is just for demo. For more correct implementation consider the other ideas proposed and consider using javax.swing.Timer

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class ListDemo extends JPanel {
    private JList list;
    private DefaultListModel listModel;
    public String match = null;

    private static final String hireString = "Highlight";
    private JTextField employeeName;

    public ListDemo() {
        super(new BorderLayout());

        listModel = new DefaultListModel();
        listModel.addElement("Test1");
        listModel.addElement("Test2");
        listModel.addElement("Test3");

        list = new JList(listModel);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        list.setSelectedIndex(0);
        list.setVisibleRowCount(5);
        list.setCellRenderer(new MyListCellRenderer());
        JScrollPane listScrollPane = new JScrollPane(list);

        JButton hireButton = new JButton(hireString);
        HireListener hireListener = new HireListener(hireButton);
        hireButton.setActionCommand(hireString);
        hireButton.addActionListener(hireListener);
        hireButton.setEnabled(false);

        employeeName = new JTextField(10);
        employeeName.addActionListener(hireListener);
        employeeName.getDocument().addDocumentListener(hireListener);
        listModel.getElementAt(list.getSelectedIndex()).toString();

        JPanel buttonPane = new JPanel();
        buttonPane.setLayout(new BoxLayout(buttonPane,
                                           BoxLayout.LINE_AXIS));
        buttonPane.add(Box.createHorizontalStrut(5));
        buttonPane.add(employeeName);
        buttonPane.add(hireButton);
        buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

        add(listScrollPane, BorderLayout.CENTER);
        add(buttonPane, BorderLayout.PAGE_END);
    }
    class MyListCellRenderer extends JLabel implements ListCellRenderer {
        public MyListCellRenderer() {
            setOpaque(true);
        }
        public Component getListCellRendererComponent(JList paramlist, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            setText(value.toString());
            if (value.toString().equals(match)) {
                setBackground(Color.BLUE);
                SwingWorker worker = new SwingWorker() {
                    @Override
                    public Object doInBackground() {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) { /*Who cares*/ }
                        return null;
                    }
                    @Override
                    public void done() {
                        match = null;
                        list.repaint();
                    }
                };
                worker.execute();
            } else
                setBackground(Color.RED);
            return this;
        }
    }
    class HireListener implements ActionListener, DocumentListener {
        private boolean alreadyEnabled = false;
        private JButton button;
        public HireListener(JButton button) {
            this.button = button;
        }
        public void actionPerformed(ActionEvent e) {
            String name = employeeName.getText();
            if (listModel.contains(name)) {
                match = name;
                list.repaint();
                employeeName.requestFocusInWindow();
                employeeName.selectAll();
                return;
            }
            if (name.equals("")) {
                Toolkit.getDefaultToolkit().beep();
                employeeName.requestFocusInWindow();
                employeeName.selectAll();
                return;
            }
            int index = list.getSelectedIndex();
            if (index == -1)
                index = 0;
            else
                index++;
            listModel.insertElementAt(employeeName.getText(), index);
            employeeName.requestFocusInWindow();
            employeeName.setText("");
            list.setSelectedIndex(index);
            list.ensureIndexIsVisible(index);
        }
        public void insertUpdate(DocumentEvent e) {
            enableButton();
        }
        public void removeUpdate(DocumentEvent e) {
            handleEmptyTextField(e);
        }
        public void changedUpdate(DocumentEvent e) {
            if (!handleEmptyTextField(e))
                enableButton();
        }
        private void enableButton() {
            if (!alreadyEnabled)
                button.setEnabled(true);
        }
        private boolean handleEmptyTextField(DocumentEvent e) {
            if (e.getDocument().getLength() <= 0) {
                button.setEnabled(false);
                alreadyEnabled = false;
                return true;
            }
            return false;
        }
    }
    private static void createAndShowGUI() {
        JFrame frame = new JFrame("ListDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JComponent newContentPane = new ListDemo();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() { createAndShowGUI(); }
        });
    }
}

Simple, set a custom ListCellRenderer to your JList using:

list.setCellRenderer(myListCellrenderer);

Now inside the overridden method getListCellRendererComponent() do something like this:

public Component getListCellRendererComponent(.....) {
    Component c = super.getListCellRendererComponent();
    c.setBackGround(Color.blue)
    return c;
}

The above example assumed that your custom renderer overrid DefaultListCellRenderer

Your custom ListCellRenderer, which implements the method getListCellRendererComponent, will have access to both the JList and the value that it is redering. This gives you a couple options for how to determine when to paint the nth row green:

  1. You could subclass JList and have the renderer ask it which color to use for the bg. The JList subclass could trigger a repaint when the business logic determines that it is time for the nth row to be green, and then start an Swing Timer to trigger a repaint returning the bg back to normal
  2. When the business logic determines when you should show the row as green, you also have the option of setting state on the backing object of the row, and test it for that state within getListCellRendererComponent, setting the bg green if the state is correct. Again, you have the option of setting an Swing Timer to revert the state on the backing object.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!