Change color of selection (after selection) in a JComboBox

老子叫甜甜 提交于 2019-12-23 02:55:10

问题


I'm writing a GUI using Swing. I have a custom written JComboBox using a ListCellRenderer and a BasicComboBoxEditor.

In my getListCellRendererComponent() method I change the color of the the list based on whether the item is "selected" (mouse is hovering above), which is nice and all, but I don't want the selection to change background color once a choice is made, which it currently does.

The first picture shows how the interface looks before a selection is made, and the second one shows how it looks after.

QUESTION

How do I change the background of the "selection" to the "stockColor"?

MCVE

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Vector;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.plaf.basic.BasicComboBoxEditor;

public class TFComboBox extends JComboBox{

    public static void main(String[] args){     
        createAndShowGUI();
    }

    public static void createAndShowGUI(){
        JFrame frame = new JFrame("MCVE");

        JPanel pane = new JPanel(new BorderLayout());
        TFComboBox cb = new TFComboBox();
        boolean[] tf = {true, false};
        cb.addItems(tf);

        JButton b = new JButton("Click me!");

        pane.add(cb, BorderLayout.CENTER);
        pane.add(b, BorderLayout.LINE_END);

        frame.add(pane);

        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private DefaultComboBoxModel model;
    private Vector<Boolean> comboBoxItems;
    private JComboBox comboBox;

    public TFComboBox(){
        comboBoxItems = new Vector<Boolean>();
        comboBoxItems.add(Boolean.TRUE);
        comboBoxItems.add(Boolean.FALSE);

        comboBox = new JComboBox(comboBoxItems);

        model = new DefaultComboBoxModel();
        setModel(model);
        setRenderer(new TrueFalseComboRenderer());
        setEditor(new TrueFalseComboEditor());
    }

    public void addItems(boolean[] items){
        for(boolean anItem : items){
            model.addElement(anItem);
        }
    }
}

class TrueFalseComboRenderer extends JPanel implements ListCellRenderer {

    private JLabel labelItem = new JLabel();
    private Color stockColor = labelItem.getBackground();

    public TrueFalseComboRenderer(){
        setLayout(new BorderLayout());
        labelItem.setOpaque(true);
        labelItem.setHorizontalAlignment(JLabel.CENTER);

        add(labelItem);

        setBackground(Color.LIGHT_GRAY);
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value, 
            int index, boolean isSelected, boolean cellHasFocus) {

        boolean tempValue = (boolean) value;    
        labelItem.setText(Boolean.toString(tempValue));

        if(isSelected){
            labelItem.setBackground(stockColor.darker());
            labelItem.setForeground(Color.WHITE);
        } else {
            labelItem.setBackground(stockColor);
            labelItem.setForeground(Color.BLACK);
        }

        return this;
    }   
}

class TrueFalseComboEditor extends BasicComboBoxEditor {

    private JLabel labelItem = new JLabel();
    private JPanel panel = new JPanel();
    private Object selectedItem;

    public TrueFalseComboEditor() {
        labelItem.setOpaque(false);
        labelItem.setHorizontalAlignment(JLabel.CENTER);
        labelItem.setForeground(Color.WHITE);

        panel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 2));
        panel.setBackground(Color.BLUE);
        panel.add(labelItem);
    }

    public Component getEditorComponent(){
        return this.panel;
    }

    public Object getItem(){
        return this.selectedItem;
    }

    public void setItem(Object item){
        if(item == null){
            return;
        }

        this.selectedItem = item;
        labelItem.setText(item.toString());
    }
}

EDIT

I've added a MCVE and as you can see it is the "problem" that the JComboBox is focused that has to do with my issue. I've placed a button next to the ComboBox to help with removing the focus from the ComboBox.

Simply doing a setFocusable(false) would fix it, but also take away some of the functionality of the rest of the program, so this is not desired.


回答1:


  • for better help sooner post an SSCCE / MCVE, short, runnable, compilable, with hardcoded value for JComboBox / XxxComboBoxModel in local variable
  • JList has Boolean array implemented as default in API (no idea whats hidden in String trueFalseItem = Boolean.toString(tempValue); and with value stored JComboBox model)
  • this is just code minimum to test isSelected and to change JList.setSelectionXxx inside DefaultListCellRenderer

for example (code in SSCCE / MCVE form)

.

.

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.SwingUtilities;

public class ComboBoxBooleanModel {

    private javax.swing.Timer timer = null;
    private Vector<Boolean> comboBoxItems;
    private JComboBox box;

    public ComboBoxBooleanModel() {
        comboBoxItems = new Vector<Boolean>();
        comboBoxItems.add(Boolean.TRUE);
        comboBoxItems.add(Boolean.FALSE);
        box = new JComboBox(comboBoxItems);
        box.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList list, Object value,
                    int index, boolean isSelected, boolean cellHasFocus) {
                Component c = super.getListCellRendererComponent(
                        list, value, index, isSelected, cellHasFocus);
                if (c instanceof JLabel) {
                    JLabel l = (JLabel) c;
                    if (Boolean.TRUE.equals(value)) {
                        l.setBackground(Color.RED);
                        if (isSelected) {
                            list.setSelectionForeground(Color.RED);
                            list.setSelectionBackground(Color.BLUE);
                        }
                    } else if (Boolean.FALSE.equals(value)) {
                        l.setBackground(Color.BLUE);
                        if (isSelected) {
                            list.setSelectionForeground(Color.BLUE);
                            list.setSelectionBackground(Color.RED);
                        }
                    }
                    return l;
                }
                return c;
            }
        });
        JFrame frame = new JFrame("");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(box);
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                box.setSelectedIndex(1);
            }
        });
        start();
    }

    private void start() {
        timer = new javax.swing.Timer(2250, updateCol());
        timer.start();
    }

    public Action updateCol() {
        return new AbstractAction("text load action") {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                if (box.getSelectedItem() == (Boolean) false) {
                    box.setSelectedItem((Boolean) true);
                } else {
                    box.setSelectedItem((Boolean) false);
                }
            }
        };
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ComboBoxBooleanModel comboBoxModel = new ComboBoxBooleanModel();
            }
        });
    }
}



回答2:


Here is a short demo of 2 JCombos, one of which will not change its background color when selected :

public static void main(String[] args){

    JFrame frame = new JFrame("Combos BG Color test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.getContentPane().setPreferredSize(new Dimension(400, 40));

    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new GridLayout(1,2));
    frame.add(mainPanel);

    JComboBox<String> aCombo = new JComboBox<>(new String[]{"A","B","C"});
    mainPanel.add(aCombo);

    JComboBox<String> bCombo = new JComboBox<>(new String[]{"1","2","3"});
    Color bgColor = bCombo.getBackground();
    bCombo.setRenderer(new DefaultListCellRenderer() {
        @Override
        public void paint(Graphics g) {
            setBackground(bgColor);
            super.paint(g);
        }
    });

    mainPanel.add(bCombo);
    frame.pack();
    frame.setVisible(true);
}

(Most of the credit goes to this answer)



来源:https://stackoverflow.com/questions/38200477/change-color-of-selection-after-selection-in-a-jcombobox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!