Search code examples
javaswingjcheckbox

Should I Extend Swing JCheckBox?


I have a Swing app with multiple JCheckBoxes. Each JCheckBox corresponds to another object of type Foo have elsewhere in my program. For each object of type Foo, I'll have one of these JCheckBoxes available for the user to click on (it tells the Foo object if they should display on the UI or not).

What I am currently doing is using the name attribute on JCheckBox as a reference back to the string "name" of the Foo object. I feel like a much cleaner solution would be to extend JCheckBox to add an extra field to it, so that the JCheckBox can keep track of which Foo object it's attached to by simply storing a reference to it. Thoughts? Do people regularly extend Swing components so that they can link the parts in the controller/view back to the model? Is there some horrible pitfall I'm going to run into?


Solution

  • It is hard to get the whole picture for this particular example without additional details. You may be able to accomplish this task using actions. See How to Use Actions for more details. Here is an example:

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.event.*;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.PrintStream;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.*;
    
    public class CheckBoxDemo {
    
        static class Foo {
            private boolean visible;
            private String name;
    
            public Foo(String name) {
                this.name = name;
            }
    
            public boolean isVisible() {
                return visible;
            }
    
            public void setVisible(boolean visible) {
                this.visible = visible;
                System.out.println(getName() + ".setVisible:" + visible);
            }
    
            public String getName() {
                return name;
            }
        }
    
        static class FooAction extends AbstractAction {
            private Foo foo;
    
            public FooAction(Foo foo) {
                super(foo.getName());
                this.foo = foo;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                JCheckBox checkBox = (JCheckBox) e.getSource();
                foo.setVisible(checkBox.isSelected());
            }
        }
    
        private static void createAndShowGUI() {
            List<Foo> fooList = new ArrayList<Foo>();
            fooList.add(new Foo("Foo1"));
            fooList.add(new Foo("Foo2"));
            fooList.add(new Foo("Foo3"));
    
            JPanel content = new JPanel(new BorderLayout());
    
            JPanel fooPanel = new JPanel();
            for (Foo foo : fooList) {
                fooPanel.add(new JCheckBox(new FooAction(foo)));
            }
    
            content.add(fooPanel, BorderLayout.NORTH);
    
            final JTextArea textArea = new JTextArea();
            textArea.setEditable(false);
            JScrollPane scrollPane = new JScrollPane(textArea);
            scrollPane.setPreferredSize(new Dimension(200, 200));
            content.add(scrollPane, BorderLayout.CENTER);
    
            JFrame frame = new JFrame("CheckBoxDemo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(content);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
    
            // just for brevity of example
            System.setOut(new PrintStream(new OutputStream() {
                @Override
                public void write(int b) throws IOException {
                    textArea.append(String.valueOf((char) b));
                }
            }));
        }
    
        public static void main(String[] args) {
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI();
                }
            });
        }
    }