javaswingnullpointerexceptionjtreejcheckbox

Exception when clicking JTree (null pointer exception)


so when i clicking the Messages tabPane containing the Jtree, this is the preview in my java swing which seems fine.

pict 1 (loading the message)

pict 2. (done)

when i click any of the checkboxes in the JTree it should be either loading(checking) or unloading(unchecking) the messages in the message list with the swingworker running to see the progress. But what happen is after i click the checkboxes (of any condition), yes the swingworker running and giving the loading/unloading progress, but after that, i get this:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "model.Message.getContents()" because "message" is null

and make the message lists is unclickable, which were clickable before i attempted to click the checkboxes in the JTree.

at the moment i dont need JTree in my purpose for learning swing, so I'm not really taking into account about this JTree lesson, but i need this to be fixed so i can keep go along with the tutorial. that's why i'm not quite sure which code are problematic and needed to put in this thread. So i'm very sorry if my question is not clear. if there still anything i have to put at this thread, please ask me i'll be happy to put it here.

this the class that mentioned in exception

public class MessagePanel extends JPanel implements ProgressDialogListener{
 public MessagePanel(JFrame parent) {
    messageListModel = new DefaultListModel();
    messageList = new JList(messageListModel);
    messageList.setCellRenderer(new MessageListRenderer());
        
    messageList.addListSelectionListener(new ListSelectionListener() {
        @Override
        public void valueChanged(ListSelectionEvent e) {
            Message message = (Message)messageList.getSelectedValue();
            textPanel.setText(message.getContents());
        }
    });
 }

this is the class and method that related with the above class

public class MessageListRenderer implements ListCellRenderer {
    private JPanel panel;
    private JLabel label;
    private Color selectedColor,normalColor;

    public MessageListRenderer() {
     //some ui settings
    }

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

        Message message = (Message)value;
        label.setText(message.getTitle());
        panel.setBackground(cellHasFocus ? selectedColor: normalColor);
        return panel;
    }
}

===================

public class TextPanel extends JPanel{
    public void setText(String text) {
        textArea.setText(text);
    }
}

===================

public class Message {
    private String title,contents;

    public Message(String title, String contents) {
        super();
        this.title = title;
        this.contents = contents;
    }

    public String getTitle() {return title;}
    public void setTitle(String title) {this.title = title;}
    public String getContents() {return contents;}
    public void setContents(String contents) {this.contents = contents;}
}

Solution

  • Your Message class constructor requires two parameters (of: String, String) in order to create an instance of Message. I have no clue what you are currently using to create you Message instances nor do I know what is storing those instances. You do need to keep track of them otherwise you will loose them to JVM Garbage Collection.

    I think perhaps you may want to modify your Message Class a little so that you can internally (or externally) store your Message instances and easily access any one of those instances when required, for example:

    public class Message {
    
        // A List Interface object to hold Message instances.
        private static java.util.List<Message> messageInstances = new java.util.ArrayList<>();
        // The OS System's New-Line character to use for console writing. 
        private final static String ls = System.lineSeparator();
    
        // Instance member variables
        private String title;
        private String contents;
    
    
        /**
         * Constructor #1
         * Does Nothing but adds the instance to the messageInstances List!
         * Relies on Setters to fill instance member variables.
         */
        public Message() {  
            messageInstances.add((this));
        }
    
        /**
         * Constructor #2
         * Contains parameters of which the arguments will fill instance member 
         * variables listed within the Parameters list below.
         * 
         * @param title (String) The Message Title.<br>
         * 
         * @param contents (String) The message content related to the above title.
         */
        public Message(String title, String contents) {
            super();
            this.title = title;
            this.contents = contents;
            messageInstances.add((this));
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getContents() {
            return contents;
        }
    
        public void setContents(String contents) {
            this.contents = contents;
        }
    
        public static java.util.List<Message> getMessageInstances() {
            return messageInstances;
        }
    
        /**
         * Removes one (or more) Message instances from the messageInstances List. 
         * This method must be supplied at least one integer index value of the 
         * Message instance to remove otherwise a Warning is displayed within the 
         * console window. Several index values can be supplied providing they are 
         * delimited with a comma or all desired Message Instance index values to 
         * remove are supplied within a Single Dimensional int[] Array.<br><br>
         * 
         * <b>Valid uses of this class method:</b><pre>
         * 
         *     removeMessageInstance(0, 4, 2, 16);
         * 
         *     OR
         * 
         *     int[] indexes = {0, 4, 2, 16};
         *     removeMessageInstance(indexes);</pre>
         * 
         * @param instanceIndexes
         */
        public static void removeMessageInstance(int... instanceIndexes) {
            int[] iIndex = null;
            if (instanceIndexes.length == 0) {
                System.err.println("Message.removeMessageInstance() method Warning!" + ls
                        + "Require an index value of the Message Instance to remove!" + ls
                        + "Ignoring Removal call!" );
                return;
            }
        
            iIndex = new int[instanceIndexes.length];
            System.arraycopy(instanceIndexes, 0, iIndex, 0, instanceIndexes.length);
        
            for (int i = 0; i < iIndex.length; i++) {
                if(iIndex[i] < 0 || iIndex[i] > messageInstances.size()) {
                    System.err.println("Message.removeMessageInstance() method Warning!" + ls 
                            + "The supplied Message Instance index value (" + iIndex[i] + ") is invalid!" + ls
                            + "Ignoring Removal call for Message Instance at Index " + iIndex[i] + "!");
                    continue;
                }
                messageInstances.remove(iIndex[i]);
            }
        }
    
        @Override
        public String toString() {
            return new StringBuilder("").append(title).append(" | ")
                                        .append(contents).toString();
        }
    }
    

    Do whatever it is you do to create Message instances.

    Now, in your MessagePanel class within the ListSelectionListener:

    public void valueChanged(ListSelectionEvent e) {
        String title = messageList.getSelectedValue().toString(); // toString() may not be required.
        List<Message> messages = Message.getMessageInstances();
        for (Message msg : messages) {
            if (msg.getTitle().equalsIgnoreCase(title)) {
                textPanel.setText(msg.getContents());
                break;
            }
        }
    }