Java Swing - JCheckbox with 3 states (full selected, partially selected and deselected) [duplicate]
Asked Answered
S

8

10

I want a JCheckbox that has 3 states as shown below:

  1. Partially Selected
  2. Unselected
  3. Full Selected

Q1. Can I use the JCheckbox for the above purpose or have to go for some custom swing component?

Souse answered 23/4, 2010 at 20:32 Comment(1)
I thought about using the same approach for filtering list. After reviewing forums I see that it is not commonly seen element (except for trees) and may confuse users. So I reconsidered using JComboBox for my filters and it is not as bad as I have originally thought.Sextuple
V
5

Here is an example for a TristateCheckBox:

http://www.javaspecialists.co.za/archive/Issue145.html

Example showing TristateCheckBox

Veinule answered 23/4, 2010 at 20:39 Comment(3)
@Peter Two questions: First, I didn't find any link for the jar file of TristateCheckBox on the site you told me. Will I need to make the jar (or classes) manually, from the code mentioned on the site? Second, there is very little difference in the appearance of selected and intermediate state of the checkbox which a normal end-user can't figure out quickly. Is there any way by which I can modify it to the one I displayed in my question. WinXp uses the same intemediate appearance that I showed in my question.Souse
@Yatendra Goel: There is no jar-File, you will have to use the files yourself (or build your own jar). Since JCheckBox does not know of this third state, the status pressed has been used in this example to render the third state, so I'm afraid there is no easy way to change the graphical representation to match the standard XP-style.Veinule
I would avoid setArmed/setPressed as a workaround tbh because it generates the wrong appearance on OSX.Resale
S
5

Oh yes, but you have to create a custom component.

Take a look at this article in the Java Specialist and see if it works for you.

It needs a bit of work in OSX though.

alt text

WinXP:

alt text

Stressful answered 23/4, 2010 at 20:40 Comment(1)
@Oscar Reyes: The link in my answer contains the revised version of this newsletter that works for Java 5 upwards :)Veinule
S
3

I dont know why anyone would give the solutions with additional icon png files while java api gives great funcionality for overriding paintIcon(..) method.

The best lightweight solution to determine tri-state CheckBox stance is IMO ClientProperty attribute.

enter image description here

/*
 * Tri-state checkbox example
 * @s1w_
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


class TCheckBox extends JCheckBox implements Icon, ActionListener {

    final static boolean MIDasSELECTED = true;  //consider mid-state as selected ?


    public TCheckBox() { this(""); }

    public TCheckBox(String text) {
        super(text);
        putClientProperty("SelectionState", 0);
        setIcon(this);
        addActionListener(this);
    }

    public TCheckBox(String text, int sel) {
        /* tri-state checkbox has 3 selection states:
         * 0 unselected
         * 1 mid-state selection
         * 2 fully selected
        */
        super(text, sel > 1 ? true : false);

        switch (sel) {
            case 2: setSelected(true);
            case 1:
            case 0:
                putClientProperty("SelectionState", sel);
                break;
           default:
                throw new IllegalArgumentException();
        }
        addActionListener(this);
        setIcon(this);
    }

    @Override
    public boolean isSelected() {
        if (MIDasSELECTED && (getSelectionState() > 0)) return true;
        else return super.isSelected();
    }

    public int getSelectionState() {
        return (getClientProperty("SelectionState") != null ? (int)getClientProperty("SelectionState") :
                                         super.isSelected() ? 2 :
                                         0);
    }

    public void setSelectionState(int sel) {
        switch (sel) {
            case 2: setSelected(true);
                    break;
            case 1: 
            case 0: setSelected(false);
                    break;
           default: throw new IllegalArgumentException();
        }
        putClientProperty("SelectionState", sel);
    }


    final static Icon icon = UIManager.getIcon("CheckBox.icon");

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        icon.paintIcon(c, g, x, y);
        if (getSelectionState() != 1) return;

        int w = getIconWidth();
        int h = getIconHeight();
        g.setColor(c.isEnabled() ? new Color(51, 51, 51) : new Color(122, 138, 153));
        g.fillRect(x+4, y+4, w-8, h-8);

        if (!c.isEnabled()) return;
        g.setColor(new Color(81, 81, 81));
        g.drawRect(x+4, y+4, w-9, h-9);
    }

    @Override
    public int getIconWidth() {
        return icon.getIconWidth();
    }

    @Override
    public int getIconHeight() {
        return icon.getIconHeight();
    }

    public void actionPerformed(ActionEvent e) {
        TCheckBox tcb = (TCheckBox)e.getSource();
        if (tcb.getSelectionState() == 0)
            tcb.setSelected(false);

        tcb.putClientProperty("SelectionState", tcb.getSelectionState() == 2 ? 0 : 
                                                     tcb.getSelectionState() + 1);

        // test
        System.out.println(">>>>IS SELECTED: "+tcb.isSelected());
        System.out.println(">>>>IN MID STATE: "+(tcb.getSelectionState()==1));
    }
}

usage: TCheckBox tcb = new TCheckBox("My CheckBox");

Skelp answered 5/11, 2014 at 4:8 Comment(1)
Works great on Windows, but not on Linux/GTKLookAndFeel. Any ideas?Hyatt
C
2

If you're trying to do a tree of checkboxes (which is a common reason to need a tri state checkbox), check out Jide Commons.

alt text

Cantus answered 23/4, 2010 at 21:22 Comment(3)
+1 Jide is my favorite frameworkStressful
Yes, I want a tree of checkboxes. I searched the site you mentioned but didn't find the page demonstrating the tree. Second, I want to use it in my commercial development so Is is free or Do I need to purchase a license?Souse
You can download the demo (jidesoft.com/products/1.4/jide_demo.jnlp) and see if it has an example with the CheckboxTree (it probably does). As far as the licensing issue, it's released under the GPL.Cantus
V
2

The UI element JCheckBox does not directly support it, but you can trick it:

//selected
checkbox.setSelected(true);

//partially selected
checkbox.getModel().setPressed(true);
checkbox.getModel().setArmed(true);

//not selected
checkbox.setSelected(false);

of course this is only the UI part, you need to implement your state machine with a custom model.

Videogenic answered 16/6, 2012 at 22:10 Comment(0)
O
1

You will need something that holds the states of the checkbox. I use a custom model.

@Override
protected void paintComponent(Graphics g) {

    getModel().setArmedForPaint(isPartial());
    getModel().setPressedForPaint(isPartial());

    super.paintComponent(g);

    getModel().setArmedForPaint(null);
    getModel().setPressedForPaint(null);
}

In your custom ToggleButtonModel

    @Override
    public boolean isArmed() {
        if (armedForPaint != null) {
            return armedForPaint.booleanValue();
        }

        return super.isArmed();
    }

    @Override
    public boolean isPressed() {
        if (pressedForPaint != null) {
            return pressedForPaint.booleanValue();
        }

        return super.isPressed();
    }
Oswell answered 16/4, 2013 at 20:28 Comment(0)
W
0

You can get this result, in this related answer:

https://mcmap.net/q/760432/-tristate-checkboxes-in-java

enter image description here

Whelm answered 9/4, 2013 at 9:33 Comment(0)
I
0

I just made a ThreeStateCheckBox class in Java 8 that employs/imitates JCheckBox, has adjustable behavior (E.g. should it react on the full width, on the full height, and where should it be placed if the component is stretched by the layout? Should the user be able to effect the indeterminate state? Should the user be able to affect it?), and looks proper in all the standard LookAndFeels (but you have to give an extra argument if you use Nimbus). Took me the last 5 hours.

Demo code is contained at the top of the class. EDIT: screenshot

Concept:

A normal JCheckBox without text is used so that look and behavior is classic, and so that the size of the box can be measured by the paintComponent code. A filled rectangle is painted for the indeterminate state. The JCheckBox is programmatically set, which does not trigger the event since an ActionListener was used.

A Boolean is used to express the state. The class itself does NOT extend a component, so it only has the essential methods. All used components are exposed.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;




/**
 * ThreeStateCheckBox by dreamspacepresident.com
 * <p>
 * v[1, 2015-11-20 13!00 UTC]
 */
final public class ThreeStateCheckBox {


    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // MAIN METHOD FOR TESTS/DEMONSTRATION
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////


    /**
     * Two checkboxes are shown. The upper one is TreeStateCheckBox, the lower one is the classic JCheckBox.
     */
    public static void main(final String[] args) {

        SwingUtilities.invokeLater(() -> {

            // PICK A LOOKANDFEEL
            final String lookAndFeelName;
            lookAndFeelName = "Nimbus";
            //            lookAndFeelName = "Metal";
            //            lookAndFeelName = "CDE/Motif";
            //            lookAndFeelName = "Windows";
            //            lookAndFeelName = "Windows Classic";
            final UIManager.LookAndFeelInfo[] lafis = UIManager.getInstalledLookAndFeels();
            boolean foundLAFI = false;
            for (UIManager.LookAndFeelInfo lafi : lafis) {
                if (lafi.getName().equalsIgnoreCase(lookAndFeelName)) {
                    try {
                        UIManager.setLookAndFeel(lafi.getClassName());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    foundLAFI = true;
                    break;
                }
            }
            if (!foundLAFI) {
                throw new Error("Unknown LookAndFeel: " + lookAndFeelName);
            }

            // CREATE AND INITIALIZE COMPONENTS
            final JFrame window = new JFrame("L&F: " + lookAndFeelName);
            final JPanel contentPane = new JPanel(new GridLayout(0, 1));
            final String cbDemoText = "bold";
            final List<JComponent> cbList = new ArrayList<>(); // Originally, I had more demos planned. I'll leave this here in case you need it.
            ThreeStateCheckBox cbThreeState;
            JCheckBox cbClassic;
            //            contentPane.setBackground(Color.MAGENTA);

            cbThreeState = new ThreeStateCheckBox(cbDemoText, null, false, true, null, null, null, null, false, false, TSCBOrientation.WEST, true, null); // NIMBUS DEMO (because of the gap)
            //            cbThreeState = new ThreeStateCheckBox(cbDemoText);
            cbClassic = new JCheckBox(cbDemoText);

            cbList.add(cbThreeState.getComponent());
            cbList.add(cbClassic);

            cbThreeState.setClientCode(b -> System.out.println("CURRENT STATE: " + b.getState() + "; PREVIOUS STATE: " + b.getPreviousState()));
            cbClassic.addActionListener(e -> System.out.println("CURRENT STATE: " + cbClassic.isSelected()));

            //            cbThreeState.setEnabled(false);
            //            cbClassic.setEnabled(false);

            //            cbClassic.setBackground(Color.ORANGE);
            //            cbThreeState.setBackground(Color.ORANGE);

            //            cbClassic.setOpaque(true);
            //            cbThreeState.setOpaque(true);

            //            cbThreeState.setText("italic");
            //            cbClassic.setText("italian");

            cbThreeState.setUserCanEffectIndeterminateState(true);


            // LAYOUT COMPONENTS
            cbList.forEach(contentPane::add);


            // INITIALIZE AND SHOW WINDOW
            window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            window.setContentPane(contentPane);
            //            window.pack();
            window.setSize(new Dimension(300, 300));
            window.setResizable(false);
            window.setLocationRelativeTo(null);
            window.setVisible(true);


            cbThreeState.setState(null);
            cbThreeState.setState(false);
            cbThreeState.setState(true);
            cbThreeState.callClientCode();
        });
    }


    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // THE ACTUAL CLASS BEGINS HERE
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////




    public enum TSCBOrientation {
        NORTHWEST, NORTH, NORTHEAST, WEST, CENTER, EAST, SOUTHWEST, SOUTH, SOUTHEAST
    }




    final public static Color DEFAULT_COLOR_OF_INDETERMINATE_STATE = new Color(0x222222);
    final public static Color DEFAULT_COLOR_OF_INDETERMINATE_STATE_WHENDISABLED = new Color(0x7f222222, true);
    final public static int DEFAULT_SIZE_OF_INDETERMINATERECTANGLE = 8;
    final public static int MIN_SIZE_OF_INDETERMINATERECTANGLE = 2;
    final private static Map<TSCBOrientation, Integer> GBC_ORIENTATION = new HashMap<>();

    static {
        GBC_ORIENTATION.put(TSCBOrientation.NORTHWEST, GridBagConstraints.NORTHWEST);
        GBC_ORIENTATION.put(TSCBOrientation.NORTH, GridBagConstraints.NORTH);
        GBC_ORIENTATION.put(TSCBOrientation.NORTHEAST, GridBagConstraints.NORTHEAST);
        GBC_ORIENTATION.put(TSCBOrientation.WEST, GridBagConstraints.WEST);
        GBC_ORIENTATION.put(TSCBOrientation.CENTER, GridBagConstraints.CENTER);
        GBC_ORIENTATION.put(TSCBOrientation.EAST, GridBagConstraints.EAST);
        GBC_ORIENTATION.put(TSCBOrientation.SOUTHWEST, GridBagConstraints.SOUTHWEST);
        GBC_ORIENTATION.put(TSCBOrientation.SOUTH, GridBagConstraints.SOUTH);
        GBC_ORIENTATION.put(TSCBOrientation.SOUTHEAST, GridBagConstraints.SOUTHEAST);
    }


    final private JPanel allContainer; // Extra step to ensure JCheckBox will have its minimum size.
    final private JPanel contentContainer;
    final private JCheckBox checkBox;
    final private JLabel label;

    private String text = null;
    private Boolean state;
    private Boolean previousState;
    private boolean userCanEffectIndeterminateState;
    private boolean userCanAffectIndeterminateState;
    private Consumer<ThreeStateCheckBox> clientCode = null;

    final private Color colorOfIndeterminateRectangle;
    final private Color colorOfIndeterminateRectangleWhenDisabled;
    final private int widthOfIndeterminateRectangle;
    final private int heightOfIndeterminateRectangle;

    private boolean enabled = true;


    public ThreeStateCheckBox() {

        this(null, false, false, true, null, null, null, null, false, false, TSCBOrientation.WEST, false, null);
    }


    public ThreeStateCheckBox(final String text) {

        this(text, false, false, true, null, null, null, null, false, false, TSCBOrientation.WEST, false, null);
    }


    /**
     * The all-constructor, called by the others.
     *
     * @param text                                      checkbox text
     * @param initialState                              whether the checkbox initially is not selelected (false),
     *                                                  selected (true), or in indeterminate state (null)
     * @param userCanEffectIndeterminateState           Seriously, it's not that hard.
     * @param userCanAffectIndeterminateState           So learn it already.
     * @param colorOfIndeterminateRectangle             When the state is indeterminate, a filled rectangle (usually
     *                                                  square) will be drawn. The default color (if value here is null)
     *                                                  is a very dark gray which visually works with all LookAndFeels.
     *                                                  (This setting can not be changed later.)
     * @param colorOfIndeterminateRectangleWhenDisabled Same, except for when the component is not enabled. The color is
     *                                                  the same, except it's only half opaque.
     * @param widthOfIndeterminateRectangle             null = default of 8, otherwise the size of the
     *                                                  indeterminate-rectangle can be defined here. (This setting can
     *                                                  not be changed later.)
     * @param heightOfIndeterminateRectangle            Same.
     * @param reactAcrossFullWidth                      The default behavior for standard JCheckBoxes is true - no
     *                                                  matter how far to the right of the box you click, even if there
     *                                                  is no text at all, the box will be clicked. The default behavior
     *                                                  (as per the other constructors) for ThreeStateCheckBox in this
     *                                                  regard is FALSE, however. (This setting can not be changed
     *                                                  later.)
     * @param reactAcrossFullHeight                     The default behavior for standard JCheckBoxes is true - no
     *                                                  matter how empty the space above and below is, the box will be
     *                                                  clicked. The default behavior (as per the other constructors)
     *                                                  for ThreeStateCheckBox in this regard is FALSE, however. If this
     *                                                  setting is true, the same setting for width is effectively true,
     *                                                  too, nothing you can do about that. (This setting can not be
     *                                                  changed later.)
     * @param orientationInAvailableSpace               If the component is stretched via its placement in the layout
     *                                                  hierarchy, as opposed to the JCheckBox, the ThreeStateCheckBox
     *                                                  can be positioned in 9 places. (This setting can not be changed
     *                                                  later.)
     * @param leaveGapBetweenBoxAndLabel                Even though JCheckBox's getIconTextGap() is queried to effect a
     *                                                  proper distance, this works only correctly for Nimbus. In all
     *                                                  other cases, the gap is too big compared to the original
     *                                                  JCheckBox. Setting this to false fixes the behavior for all
     *                                                  other LookAndFeels, because it just leave *no* gap at all.
     * @param clientCode                                The code to be executed if THE USER clicks the checkbox. The
     *                                                  code will receive a reference to the ThreeStateCheckBox, so they
     *                                                  can query the new (=current) and previous state of it.
     */
    public ThreeStateCheckBox(final String text, final Boolean initialState, final boolean userCanEffectIndeterminateState, final boolean userCanAffectIndeterminateState, final Color colorOfIndeterminateRectangle, final Color colorOfIndeterminateRectangleWhenDisabled, final Integer widthOfIndeterminateRectangle, final Integer heightOfIndeterminateRectangle, final boolean reactAcrossFullWidth, final boolean reactAcrossFullHeight, final TSCBOrientation orientationInAvailableSpace, final boolean leaveGapBetweenBoxAndLabel, final Consumer<ThreeStateCheckBox> clientCode) {


        // INITIALIZE CONSTRUCTOR VALUES
        state = initialState;
        previousState = state;
        this.userCanEffectIndeterminateState = userCanEffectIndeterminateState;
        this.userCanAffectIndeterminateState = userCanAffectIndeterminateState;

        if (colorOfIndeterminateRectangle == null) {
            this.colorOfIndeterminateRectangle = DEFAULT_COLOR_OF_INDETERMINATE_STATE;
        } else {
            this.colorOfIndeterminateRectangle = colorOfIndeterminateRectangle;
        }
        if (colorOfIndeterminateRectangleWhenDisabled == null) {
            this.colorOfIndeterminateRectangleWhenDisabled = DEFAULT_COLOR_OF_INDETERMINATE_STATE_WHENDISABLED;
        } else {
            this.colorOfIndeterminateRectangleWhenDisabled = colorOfIndeterminateRectangleWhenDisabled;
        }

        if (widthOfIndeterminateRectangle == null) {
            this.widthOfIndeterminateRectangle = DEFAULT_SIZE_OF_INDETERMINATERECTANGLE;
        } else {
            this.widthOfIndeterminateRectangle = Math.max(MIN_SIZE_OF_INDETERMINATERECTANGLE, widthOfIndeterminateRectangle);
        }
        if (heightOfIndeterminateRectangle == null) {
            this.heightOfIndeterminateRectangle = DEFAULT_SIZE_OF_INDETERMINATERECTANGLE;
        } else {
            this.heightOfIndeterminateRectangle = Math.max(MIN_SIZE_OF_INDETERMINATERECTANGLE, heightOfIndeterminateRectangle);
        }

        Integer orientation = GBC_ORIENTATION.get(orientationInAvailableSpace);
        if (orientation == null) {
            orientation = GridBagConstraints.CENTER;
        }
        this.clientCode = clientCode;


        // CREATE COMPONENTS
        label = new JLabel();
        checkBox = new JCheckBox() {

            @Override
            protected void paintComponent(final Graphics g) {

                super.paintComponent(g);

                if (state == null) {

                    final int w = getWidth();
                    final int h = getHeight();
                    final int wOdd = w % 2;
                    final int hOdd = h % 2;
                    final int centerX = w / 2;
                    final int centerY = h / 2;
                    final int rwHalf = Math.max(1, ThreeStateCheckBox.this.widthOfIndeterminateRectangle / 2);
                    final int rhHalf = Math.max(1, ThreeStateCheckBox.this.heightOfIndeterminateRectangle / 2);
                    final int rw = rwHalf * 2 + wOdd;
                    final int rh = rhHalf * 2 + hOdd;

                    if (isEnabled()) {
                        g.setColor(ThreeStateCheckBox.this.colorOfIndeterminateRectangle);
                    } else {
                        g.setColor(ThreeStateCheckBox.this.colorOfIndeterminateRectangleWhenDisabled);
                    }
                    g.fillRect(centerX - rwHalf, centerY - rhHalf, rw, rh);
                }
            }
        };
        final int gap;
        if (leaveGapBetweenBoxAndLabel) {
            gap = checkBox.getIconTextGap();
        } else {
            gap = 0;
        }

        contentContainer = new JPanel(new BorderLayout(gap, 0));
        allContainer = new JPanel(new GridBagLayout());


        // INITIALIZE COMPONENTS
        setOpaque(false);
        if (state != null && state) {
            checkBox.setSelected(true);
        }
        setText(text);


        // LAYOUT COMPONENTS
        contentContainer.add(checkBox, BorderLayout.WEST);
        contentContainer.add(label, BorderLayout.CENTER);
        final GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = orientation;
        if (reactAcrossFullWidth) {
            gbc.fill = GridBagConstraints.HORIZONTAL;
        }
        gbc.weightx = 1;
        gbc.weighty = 1;
        allContainer.add(contentContainer, gbc);


        // CREATE LISTENERS
        final ActionListener checkBoxListener = e -> {
            if (!enabled) {
                return;
            }
            if (state == null) {
                if (ThreeStateCheckBox.this.userCanAffectIndeterminateState) {
                    setState(false);
                } else {
                    setState(null);
                }
            } else if (!state) {
                setState(true);
            } else {
                if (ThreeStateCheckBox.this.userCanEffectIndeterminateState) {
                    setState(null);
                } else {
                    setState(false);
                }
            }
            callClientCode();
        };
        final MouseListener labelAndPanelListener = new MouseAdapter() {

            final private ButtonModel model = checkBox.getModel();
            private boolean lmbIsDown = false;


            @Override
            public void mousePressed(final MouseEvent e) {

                if (e.getButton() == MouseEvent.BUTTON1) {
                    lmbIsDown = true;
                    model.setPressed(true);
                    model.setArmed(true);
                }
            }


            @Override
            public void mouseReleased(final MouseEvent e) {

                if (e.getButton() == MouseEvent.BUTTON1) {
                    lmbIsDown = false;
                    model.setPressed(false);
                    model.setArmed(false);
                }
            }


            @Override
            public void mouseEntered(final MouseEvent e) {

                model.setArmed(lmbIsDown);
            }


            @Override
            public void mouseExited(final MouseEvent e) {

                model.setArmed(false);
            }

        };


        // ASSIGN LISTENERS
        checkBox.addActionListener(checkBoxListener);
        checkBox.addMouseListener(labelAndPanelListener); // Necessary or the behavior will look different when the mouse moves while button is down.
        label.addMouseListener(labelAndPanelListener);
        contentContainer.addMouseListener(labelAndPanelListener);
        if (reactAcrossFullHeight) {
            allContainer.addMouseListener(labelAndPanelListener);
        }
    }


    public void setEnabled(final boolean enabled) {

        if (enabled == this.enabled) {
            return;
        }
        this.enabled = enabled;
        checkBox.setEnabled(enabled);
        label.setEnabled(enabled);
        contentContainer.setEnabled(enabled);
    }


    public boolean isEnabled() {

        return enabled;
    }


    public Color getBackground() {

        return allContainer.getBackground();
    }


    public void setBackground(final Color color) {

        if (color == null) {
            return;
        }
        checkBox.setBackground(color);
        label.setBackground(color);
        contentContainer.setBackground(color);
        allContainer.setBackground(color);
    }


    public boolean isOpaque() {

        return allContainer.isOpaque();
    }


    public void setOpaque(final boolean opaque) {

        checkBox.setOpaque(opaque);
        label.setOpaque(opaque);
        contentContainer.setOpaque(opaque);
        allContainer.setOpaque(opaque);
    }


    public JPanel getComponent() {

        return allContainer;
    }


    public JPanel getCenterContainer() {

        return contentContainer;
    }


    public JCheckBox getJCheckBox() {

        return checkBox;
    }


    public JLabel getJLabel() {

        return label;
    }


    public boolean canUserEffectIndeterminateState() {

        return userCanEffectIndeterminateState;
    }


    public void setUserCanEffectIndeterminateState(final boolean userCanEffectIndeterminateState) {

        this.userCanEffectIndeterminateState = userCanEffectIndeterminateState;
    }


    public boolean canUserAffectIndeterminateState() {

        return userCanAffectIndeterminateState;
    }


    public void setUserCanAffectIndeterminateState(final boolean userCanAffectIndeterminateState) {

        this.userCanAffectIndeterminateState = userCanAffectIndeterminateState;
    }


    /**
     * Sets the state to the new state IF IT IS DIFFERENT, which is relevant because of the previousState variable.
     * <p>
     * Does NOT call the client code! You would have to do this yourself.
     *
     * @param newState null = indeterminate, false = not selected, true = selected
     */
    public void setState(final Boolean newState) {

        checkBox.setSelected(newState != null && newState);
        if (newState == state) {
            return;
        }
        previousState = state;
        state = newState;
        checkBox.repaint();
    }


    public Boolean getState() {

        return state;
    }


    public Boolean getPreviousState() {

        return previousState;
    }


    public void setClientCode(final Consumer<ThreeStateCheckBox> clientCode) {

        this.clientCode = clientCode;
    }


    public Consumer<ThreeStateCheckBox> getClientCode() {

        return clientCode;
    }


    /**
     * Convenience method so that you don't have to keep the reference around in case you need an extra call.
     */
    public void callClientCode() {

        if (clientCode != null) {
            clientCode.accept(this);
        }
    }


    public void setText(final String newText) {

        if (newText == null || newText.trim().isEmpty()) {
            text = null;
        } else {
            text = newText;
        }
        label.setText(text);
    }


    public String getText() {

        return text;
    }


}
Incarnation answered 20/11, 2015 at 13:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.