HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Initializing JTree

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
initializingjtreestackoverflow

Problem

I have a class called Piece, and many many subclasses of Piece. I want to add an instance of every single subclass of Piece (under the pieces package) to my JTree. Currently, I have this class with a huge function (well, 57 lines, but still) that increases in size every time I add functionality to my program.

My initial approach to this was "Hey, let's just use reflection or something to find out all of the classes under the package pieces and add them to the tree!" but this SO question shot that down. My second, working approach is to add them all manually by hand. This seems like too much work though and it seems like there would be a better way to do this.

As always, miscellaneous comments on my code are very welcome.

initTree()

private void initTree(final UserInterface userInterface) {
    tree = new JTree(createTree());
    tree.setRootVisible(false);
    tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

    tree.addTreeSelectionListener(new TreeSelectionListener(){
        @Override
        public void valueChanged(TreeSelectionEvent e) {
             DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                       tree.getLastSelectedPathComponent();

             if (node == null){
                 return;
             }

             if (node.isLeaf() && node.getUserObject() instanceof Piece) {
                 Piece pieceCreated = (Piece) ((Piece)node.getUserObject()).getInstance();
                 userInterface.space.addPiece(pieceCreated);
             }
        }
    });
    add( new JScrollPane(tree), BorderLayout.CENTER );
}


createTree()

```
private DefaultMutableTreeNode createTree(){
//create the root node
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
//create the child nodes
DefaultMutableTreeNode gatesNode = new DefaultMutableTreeNode("Gates");

DefaultMutableTreeNode arithmeticNode = new DefaultMutableTreeNode("Arithmetic"

Solution

public enum PieceGroups{

    BITWISE(BitwiseAnd.class, BitwiseNand.class, BitwiseNor.class, BitwiseNot.class,
            BitwiseOr.class, BitwiseXor.class, BitwiseXnor.class, BitwiseLeftshift.class,
            BitwiseRightshift.class),
    ARITHMETIC(Add.class, Substract.class, Multiply.class, Divide.class, Modulo.class, Random.class);

    private Set classSet = new HashSet();

    private PieceGroups(Class... classes) {
        for (Class theClass : classes) {
            try {
                Constructor construtor = theClass.getDeclaredConstructor(int.class, int.class);
                classSet.add((Piece) construtor.newInstance(0, 0));
            } catch (NoSuchMethodException ex) {
                processException();
            } catch (SecurityException ex) {
                processException();
            } catch (InstantiationException ex) {
                processException();
            } catch (IllegalAccessException ex) {
                processException();
            } catch (IllegalArgumentException ex) {
                processException();
            } catch (InvocationTargetException ex) {
                 processException();
            }
        }
    }

    public Set getClasses () {
        return classSet;
    }

    private void processException () {
        throw new IllegalArgumentException("Something went wrong with the init of the Enum");
    }
}


Explication :

We create an enum, still the best singleton what there is.

Then the states of the enum are grouping where the Piece (sub)class can have, like the Bitwise and Arithmetic you showed.

Constructor of the enum is vararg, so you can give up as many classes as you want with one group.

We create an instance of the class in the constructor with reflection.
At the moment I saw that all your classes have an constructor with 2 ints, so I rely that is for all the implementations of like that.

An IllegalArgumentException is thrown when your enum can't be created by an fault (class not found, constructor not present,...)

You can also just skip that class at instanciation but then you never know when something went wrong.

At last, just ask PieceGroups.BITWISE.getClasses() and you will have a set of the corresponding group.

Code Snippets

public enum PieceGroups{

    BITWISE(BitwiseAnd.class, BitwiseNand.class, BitwiseNor.class, BitwiseNot.class,
            BitwiseOr.class, BitwiseXor.class, BitwiseXnor.class, BitwiseLeftshift.class,
            BitwiseRightshift.class),
    ARITHMETIC(Add.class, Substract.class, Multiply.class, Divide.class, Modulo.class, Random.class);

    private Set<Piece> classSet = new HashSet<Piece>();

    private PieceGroups(Class... classes) {
        for (Class theClass : classes) {
            try {
                Constructor construtor = theClass.getDeclaredConstructor(int.class, int.class);
                classSet.add((Piece) construtor.newInstance(0, 0));
            } catch (NoSuchMethodException ex) {
                processException();
            } catch (SecurityException ex) {
                processException();
            } catch (InstantiationException ex) {
                processException();
            } catch (IllegalAccessException ex) {
                processException();
            } catch (IllegalArgumentException ex) {
                processException();
            } catch (InvocationTargetException ex) {
                 processException();
            }
        }
    }

    public Set<Piece> getClasses () {
        return classSet;
    }

    private void processException () {
        throw new IllegalArgumentException("Something went wrong with the init of the Enum");
    }
}

Context

StackExchange Code Review Q#48541, answer score: 5

Revisions (0)

No revisions yet.