HI guys,
I'm trying to build a small GUI application where users can input text (in a JTextArea) and by pressing a button, you get a summary of how many times each word in the text has occurred.
So here come the questions.
First, the GUI itself. The way I envisage it to be built is with a JLabel on the top, explaining briefly what the application is about, JTextArea holding the text to process, another JTextArea to hold the results, a JPanel with two buttons, a "process button" to kick things off and let the application count the words in the text and a "clear" button which clears both JTextAreas.
Something like this:

-JFrame (default BorderLayout)
    -JPanel griBagLayout(positioned North)
        -JLabel 
        -JTextArea for sample text
    -JPanel griBagLayout (positioned Center)
        -JButton to process
        -JButton to clear first JTextArea
    -JTextArea for result (positioned South)

As far as the functionality is concerned instead, I was thinking to have a named handler class with a constructor taking a false or true parameter to determine which button is being pressed and act as a consequence of that: if the parameter is true, then it's the clear button, therefore clear everything, if true is the process button. So, something like this:

 ...
    clearButton.addActionListener(new ButtonHandler(true));
    processButton.addActionListener(new ButtonHandler(false));
    ...

Is that a good way to distinguish the buttons?

Finally, the functionality to process the text. I want to be able to process a lot of text, not just a few sentences. After reading here and there I was thinking to perhaps save all that text in the JTextArea in a String variable, use the the String's split method (split at a blank space) so that everything goes into an array and thn implement some kind of counter - I haven't thought exactly what kind of counter as yet though - do you guys reckon that would work?
thanks

Best create a separate handler class per button (unless the buttons have very similar functionality).
As to the counting, traditional mechanism would use a HashMap<String, Integer>

Thanks.

Best create a separate handler class per button (unless the buttons have very similar functionality).

Flicking through some code examples in the book, I can see that maybe, what you suggested, is better achieved with anonymous classes rather than named classes. WOuld it be better if I use those do you think?

As to the counting, traditional mechanism would use a HashMap<String, Integer>

OK, no problem, I've used it before. Spo presumably I'll do what I've mentioned before (array and split to deal with the text) and then populate the HashMap with the words (key) and the number of occurences (values). Did I understand it correctly?

Edited 1 Year Ago by Violet_82

Anonymous classes are good if they are small, but if they are more than few lines the code gets hard to read, in which case a named inner class is better. (See how I avoided mentioning lambdas there?).

eh eh, noticed you haven't mentioned them :-). I'll get coding and post the results here as soon as I have something

Right, I quickly knocked off something, and soon run into troubles. The GUI is set up - although I've decided that I will redo it later with a GridBagLayout as I don't seem to be able to display things the way I want, especially when it comes to add padding etc. I say "later" because I would like to get the whole thing to work first, know that it works and then mess around with it.
wordCount.jpg
Here is the code and then then I'll explain the issue:

 /*WordCount.java
Application determines how many times a word has occurred in the text given
*/
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;
public class WordCount extends JFrame{
    private JPanel buttonsPanel;
    private JPanel topPanel;
    private JTextArea textInput;
    private JTextArea textOutput;
    private JButton processButton;
    private JButton clearButton;
    private JLabel instructions;
    private BorderLayout frameLayout;
    private BorderLayout topPanelLayout;
    private GridLayout buttonsPanelLayout;
    //constructor
    public WordCount(){
        super("Word count application");
        JPanel buttonsPanel = new JPanel();//holds the two buttons
        JPanel topPanel = new JPanel();//holds the textArea and jlabel
        JTextArea textInput = new JTextArea(10,15);//holds the input text
        JTextArea textOutput = new JTextArea(10,15);//hold the output text
        JButton processButton = new JButton("Count");//action abutton
        JButton clearButton = new JButton("Clear");//to clear textArea
        JLabel instructions = new JLabel("Copy and paste text in the below text area, click Count to count the words.\n");//holding instructions
        BorderLayout frameLayout = new BorderLayout();//for JFrame
        BorderLayout topPanelLayout = new BorderLayout();//for top level panel
        GridLayout buttonsPanelLayout = new GridLayout(1,2,5,5);//for buttons       
        setLayout(frameLayout);//set layout of Frame
        topPanel.setLayout(topPanelLayout);//set topPanel layout
        topPanel.add(instructions, BorderLayout.NORTH);//add JLabel to topPanel
        instructions.setOpaque(true);//need this to be able to change the colour
        instructions.setBackground(Color.CYAN);     
        topPanel.add(new JScrollPane(textInput), BorderLayout.CENTER);//add textInput to topPanel
        buttonsPanel.setLayout(buttonsPanelLayout);//set buttonsPanel layout
        buttonsPanel.add(processButton);//add processButton to panel
        buttonsPanel.add(clearButton);//add clearButton to panel        
        add(topPanel, BorderLayout.NORTH);//add topPanel to JFrame
        add(buttonsPanel, BorderLayout.CENTER);//add buttonsPanel to JFrame 
        add(new JScrollPane(textOutput), BorderLayout.SOUTH);//add textOutput to JFrame
        textOutput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setText(" ");
        textOutput.setText(" ");
        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        processButton.addActionListener(handler1);
        clearButton.addActionListener(handler2);

    }//end of constructor
    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){

        }//end of actionPerformed
    }//end of inner class
    private class ClearButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            textInput.setText(" ");
            textOutput.setText(" ");
        }//end of actionPerformed
    }//end of inner class
}//end of WordCount class


/*WordCountTest.java
    WordCountTest to test the class
*/
import javax.swing.JFrame;
public class WordCountTest{
    public static void main(String[] args){
        WordCount wordCount = new WordCount();
        wordCount.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        wordCount.setSize(900, 800);
        wordCount.pack();
        wordCount.setVisible(true);
    }
}//end of WordCountTest

I've used two named classes for my event handling, one for each text area:

ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        processButton.addActionListener(handler1);
        clearButton.addActionListener(handler2);

    }//end of constructor
    //inner class for event handlings
        private class ProcessButtonHandling implements ActionListener{
            public void actionPerformed(ActionEvent event){

            }//end of actionPerformed
        }//end of inner class
        private class ClearButtonHandling implements ActionListener{
            public void actionPerformed(ActionEvent event){
                textInput.setText(" ");
                textOutput.setText(" ");
            }//end of actionPerformed
        }//end of inner class    

I started coding the clear button, as I thought that'll be the easier one (!), and what I want is to reset the fields to empty when the clear button is clicked. I had a look at the API and the best way to do that seems to be using setText(""). The application compiles but at execution time (when I click the clear button) I get some error in the console:

G:\JAVA\GUI\2015\createFrames\word_counter>javac *.java    
G:\JAVA\GUI\2015\createFrames\word_counter>java WordCountTest
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at WordCount$ClearButtonHandling.actionPerformed(WordCount.java:70)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$200(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

It doesn't seem to be happy with me clearing the text. I tried a few things, like using only one event handling class - I thought that perhaps that was the problem - but still no joy. I've also thought that perhaps I'm not giving any value to the textAreas so before the event handling bits I've set the text to empty, still nothing. Not quite sure what I've got wrong.

the UI is the last (and least important part) you should work on. Does your code work if you don't use a UI?

hi stultuske, I have this tendency of developing the GUI first...sorry, it's that I don't know how to test that the buttons are working if the GUI isn't there really...in anycase, if you let me know how I can test my appplication without GUI and that helps, more than happy to do it.
What I can say is that the GUI does work because I tested it, and if I remove the

textInput.setText(" ");
textOutput.setText(" ");

from the event handling class, I get no errors

private class ClearButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            textInput.setText(" ");
            textOutput.setText(" ");
        }//end of actionPerformed
    }//end of inner class

I thought it might have been a problem with scope, but the textInput and textOutput are declared private, the constructor position them where they should be and initialize them to be empty and the actionPerformed() method empties them again when needed

Edited 1 Year Ago by Violet_82

You are doing it backward if you attempt to implement the program in GUI before you complete the program logic. Did you learn it this way from a classroom? Or did you self-learn it?

What you need to do is to implement it without GUI. First, implement a class that can take a string, and it can count words.

// i.e.
// Break it out to be a class so you can separately test it
//   and/or add more features later on
// It could also be a private class/method inside your GUI if it is
//   small enough
class Words {
  public Words() { }  // depends on how you want it to be
  public static HashMap<String, Integer> countWords(String str) {
    ...
    return numberOfWords;  // whatever you want
  }

  // if it is a separate class, you can test its functionality
  public static void main(String[] args) {
     HashMap<String, Integer> cw = Words.countWords("Whatever string you want it to be counted");
     // then display the result to see if the method works properly
  }
}

After that, use the class inside your GUI. The count button click will call the method inside actionPerformed() once the button is clicked.

// i.e.
public void actionPerformed(ActionEvent event) {
  if (event.getSource() == processButton) {  // check if process button is clicked
    HashMap<String, Integer> countWords = Words.countWords(textInput.getText());
    // then do whatever you want...
  }
}

Hope this help clearing it up...

Edited 1 Year Ago by Taywin

Comments
Yes, absolutely right

OK thanks for the feedback guys. Scrap all the code I've done, I'm starting from scratch with a console app and trying to do what you say.
Self-learn it Taywin I'm afraid. Sooner or later I should start following the good practice, so let's start now. I'll come back with some code soon
thanks

Hi guys OK so I've done some work and made some changes to your code as well Tywin, hope that's OK, but I'm a bit unsure as to how to count words with the hashmap. Let's see first what I've done so far: the application is now a console one, it creates a string, removes ",.:;" and splits it into an array using space as delimiter:

/*WordCount.java
Application determines how many times a word has occurred in the text given
*/
//for the map
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.StringTokenizer;
public class WordCount{
    private String stringToTest;
    Map<String,Integer> mp = new HashMap<String, Integer>();//declaring a map object
    //constructor
    public WordCount(){
        stringToTest = "This is the string I want to test, and I'm curious to see the results.";
        processString(getString());//call function to split string
    }//end of constructor   
    public String getString(){
        return stringToTest;
    }
    public void printInfo(){
        System.out.printf("%s ", getString());
    }

    private void processString(String testingString){       
        //String[] tokens = testingString.split("(?=[,.])|\\s+");
        testingString = testingString.replaceAll("[,.;:]","");//remove the characters in brackets and replace them with nothing
        String[] tokens = testingString.split(" ");//split string using space as delimiter
        System.out.printf("Number of elements: %d\nTokens are \n", tokens.length);
        //print to test
        for(String token : tokens){
            System.out.println(token);
        }

    }
}//end of WordCount class



/*WordCountTest.java
    WordCountTest to test the class
*/

public class WordCountTest{
    public static void main(String[] args){
        WordCount wordCount = new WordCount();  
        wordCount.printInfo();
    }
}//end of WordCountTest

Now I have to use the hashmap to count the words. Here is some pseudocode, is this a good approach?

loop thru strings array
        check if current string is in hashmap
        if so
            increase Integer by 1
        if not
            push string into hashmap

If correct, is it possible to incremement only Integer in the hashmap leaving the key untouched? I know that there is a method put() to add key and value to the hashmap, but I can't find any method that allows me to change the value only http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
EDIT: ah, found this method public boolean containsKey(Object value), which allows me to check the key

Edited 1 Year Ago by Violet_82

I went for it and implemented the pseudocode (sorry I asked about the pseudocode in case I was completely off). Anyway, here is the final code, and it all seems to work, even if there is one thing that really bothers me. Let's look at the code first (the WordCountTest.java file is the same as before so I haven't included it):

/*WordCount.java
Application determines how many times a word has occurred in the text given
*/
//for the map
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.StringTokenizer;
public class WordCount{
    private String stringToTest;
    private String[] tokens;
    Map<String,Integer> mp = new HashMap<String, Integer>();//declaring a map object
    //constructor
    public WordCount(){
        stringToTest = "This is the string I want to test, and I'm curious to see what the result is as I'm curious.";
        processString(getString());//call function to split string
        mapWords();//count words and place results in the hashmap
        printMap();//print the map values and keys
    }//end of constructor   
    public String getString(){
        return stringToTest;
    }
    public void printInfo(){
        System.out.printf("%s ", getString());
    }

    public void processString(String testingString){        
        //String[] tokens = testingString.split("(?=[,.])|\\s+");
        testingString = testingString.replaceAll("[,.;:]","");//remove the characters in brackets and replace them with nothing
        tokens = testingString.split(" ");//split string using space as delimiter
        System.out.printf("Number of elements: %d\nTokens are \n", tokens.length);
        //print to test
        for(String token : tokens){
            System.out.println(token);
        }       
    }
    public void mapWords(){
        for(int i = 0; i < tokens.length; i++){
            if(mp.containsKey(tokens[i])){
                //increment Integer
                mp.put(tokens[i], mp.get(tokens[i]) + 1);//add it to the hashmap and increment integer
            } 
            else{
                mp.put(tokens[i],1);//add it to the hashmap
            }
        }
    }
    public void printMap(){
        for(Map.Entry<String, Integer> entry : mp.entrySet()){//loop thru map to print data
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
    }
}//end of WordCount class

This is the result I get for this string "This is the string I want to test, and I'm curious to see what the result is as I'm curious."

G:\JAVA\GUI\2015\createFrames\word_counter\test>java WordCountTest
Number of elements: 20
Tokens are
This
is
the
string
I
want
to
test
and
I'm
curious
to
see
what
the
result
is
as
I'm
curious
Key = to, Value = 2
Key = result, Value = 1
Key = is, Value = 2
Key = I'm, Value = 2
Key = test, Value = 1
Key = as, Value = 1
Key = the, Value = 2
Key = This, Value = 1
Key = I, Value = 1
Key = and, Value = 1
Key = curious, Value = 2
Key = see, Value = 1
Key = what, Value = 1
Key = string, Value = 1
Key = want, Value = 1
This is the string I want to test, and I'm curious to see what the result is as I'm curious.
G:\JAVA\GUI\2015\createFrames\word_counter\test>

My question now: I have to admit a bit of this has been trial and error, like updating the value in the hashtable. From what I've read there isn't a way to do just that, that's why I'm overwriting the value and adding one to it.
What bothers me though is this:

//increment Integer
mp.put(tokens[i], mp.get(tokens[i]) + 1);//add it to the hashmap and increment integer

This line is supposed to,as mentioned, insert the pair key-value in the map and increment the Integer by one: but how does it actually work? I mean I would have thought that by saying tokens[i]) + 1 I somewhow increment not only the value as tokens[i] represents a String and not an Integer object, so it's like incrementing a string?! It might be a stupid question, but I'm struggling to understand this...
Finally, if everybody is happy with the code, can I move to the GUI phase, or is there any other functionality I need to code in the console? There is the "clear" button functionality as well, but I could code it in the GUI

mp is a map of strings to integers, so the arithmetic works on the values correctly. tokens is a string, but the value you are adding to is mp.get(tokens[i]), which is the integer value

With java 8 you can simplify the code with a getOrDefault that will give you a default value of 0 if there is no entry for that key...

Mp.put(key, mp.getOrDefault(key, 0) +1))

No need to have an if test for whether the entry exists or not.

Oh I see, that's because the method get() returns the value and not the key! I got it!

No need to have an if test for whether the entry exists or not.

Definitely nicer in Java 8 :-)!
OK, so I'll move on and build the GUI then. I divided everything in functions so hopefully it will be easy to call the right one at the right time. Will post back when I get the GUI working.

Right, OK, so I've implemented the GUI now with the logic of the console application, but I'm still facing the same errors (I haven't implemented the clear button as yet, I was working on the Count button first).
Here are the two new files:

/*WordCount.java
Application determines how many times a word has occurred in the text given
*/
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JScrollPane;
import java.awt.Insets;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.StringTokenizer;
public class WordCount extends JFrame{
    private JPanel buttonsPanel;
    private JPanel topPanel;
    private JTextArea textInput;
    private JTextArea textOutput;
    private JButton processButton;
    private JButton clearButton;
    private JLabel instructions;
    private BorderLayout frameLayout;
    private BorderLayout topPanelLayout;
    private GridLayout buttonsPanelLayout;
    private String stringToTest;//holds string pasted in textarea
    private String[] tokens;//array of tokenized strings
    Map<String,Integer> mp = new HashMap<String, Integer>();//declaring a map object
    //constructor
    public WordCount(){
        super("Word count application");
        JPanel buttonsPanel = new JPanel();//holds the two buttons
        JPanel topPanel = new JPanel();//holds the textArea and jlabel
        JTextArea textInput = new JTextArea(10,15);//holds the input text
        JTextArea textOutput = new JTextArea(10,15);//hold the output text
        stringToTest = "";//initialize to empty string
        JButton processButton = new JButton("Count");//action abutton
        JButton clearButton = new JButton("Clear");//to clear textArea
        JLabel instructions = new JLabel("Copy and paste text in the below text area, click Count to count the words.\n");//holding instructions
        BorderLayout frameLayout = new BorderLayout();//for JFrame
        BorderLayout topPanelLayout = new BorderLayout();//for top level panel
        GridLayout buttonsPanelLayout = new GridLayout(1,2,5,5);//for buttons       
        setLayout(frameLayout);//set layout of Frame
        topPanel.setLayout(topPanelLayout);//set topPanel layout
        topPanel.add(instructions, BorderLayout.NORTH);//add JLabel to topPanel
        instructions.setOpaque(true);//need this to be able to change the colour
        instructions.setBackground(Color.CYAN);     
        topPanel.add(new JScrollPane(textInput), BorderLayout.CENTER);//add textInput to topPanel
        buttonsPanel.setLayout(buttonsPanelLayout);//set buttonsPanel layout
        buttonsPanel.add(processButton);//add processButton to panel
        buttonsPanel.add(clearButton);//add clearButton to panel        
        add(topPanel, BorderLayout.NORTH);//add topPanel to JFrame
        add(buttonsPanel, BorderLayout.CENTER);//add buttonsPanel to JFrame 
        add(new JScrollPane(textOutput), BorderLayout.SOUTH);//add textOutput to JFrame
        textOutput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setMargin(new Insets(5,5,5,5));//sets margins inside the element      
        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        processButton.addActionListener(handler1);
        clearButton.addActionListener(handler2);
    }//end of WordCount constructor
    public String getString(){
        return stringToTest;
    }
    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            stringToTest = textInput.getText();
            processString(getString());//call function to split string
            mapWords();//count words and place results in the hashmap
            printMap();//print the map values and keys in the textArea
        }//end of actionPerformed
    }//end of inner class
    private class ClearButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){

        }//end of actionPerformed
    }//end of inner class
    public void processString(String testingString){        
        //String[] tokens = testingString.split("(?=[,.])|\\s+");
        testingString = testingString.replaceAll("[,.;:]","");//remove the characters in brackets and replace them with nothing
        tokens = testingString.split(" ");//split string using space as delimiter
        /* System.out.printf("Number of elements: %d\nTokens are \n", tokens.length);
        //print to test
        for(String token : tokens){
            System.out.println(token);
        }    */ 
    }
    public void mapWords(){
        for(int i = 0; i < tokens.length; i++){
            if(mp.containsKey(tokens[i])){
                //increment Integer
                mp.put(tokens[i], mp.get(tokens[i]) + 1);//add it to the hashmap and increment integer
            } 
            else{
                mp.put(tokens[i],1);//add it to the hashmap
            }
        }
    }
    public void printMap(){
        for(Map.Entry<String, Integer> entry : mp.entrySet()){//loop thru map to print data
            //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            textOutput.append("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
    }

}//end of WordCount




/*WordCountTest.java
    WordCountTest to test the class
*/
import javax.swing.JFrame;
public class WordCountTest{
    public static void main(String[] args){
        WordCount wordCount = new WordCount();
        wordCount.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        wordCount.setSize(900, 800);
        wordCount.pack();
        wordCount.setVisible(true);

    }
}//end of WordCountTest

When I type a sentence in the input textArea and press the Count button, this is what I get in the console:

G:\JAVA\GUI\2015\createFrames\word_counter\gui>javac *.java

G:\JAVA\GUI\2015\createFrames\word_counter\gui>java WordCountTest
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at WordCount$ProcessButtonHandling.actionPerformed(WordCount.java:74)
        at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
        at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
        at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
        at java.awt.Component.processMouseEvent(Unknown Source)
        at javax.swing.JComponent.processMouseEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
        at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$200(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

So these are the only new things I've added:

private String stringToTest;//holds string pasted in textarea
    private String[] tokens;//array of tokenized strings
    Map<String,Integer> mp = new HashMap<String, Integer>();//declaring a map object
    //constructor
    public WordCount(){
    ...
    }//end of constructor
    public String getString(){
        return stringToTest;
    }
    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            stringToTest = textInput.getText();
            processString(getString());//call function to split string
            mapWords();//count words and place results in the hashmap
            printMap();//print the map values and keys in the textArea
        }//end of actionPerformed
    }//end of inner class
    ...
    public void processString(String testingString){        
        //String[] tokens = testingString.split("(?=[,.])|\\s+");
        testingString = testingString.replaceAll("[,.;:]","");//remove the characters in brackets and replace them with nothing
        tokens = testingString.split(" ");//split string using space as delimiter
        /* System.out.printf("Number of elements: %d\nTokens are \n", tokens.length);
        //print to test
        for(String token : tokens){
            System.out.println(token);
        }    */ 
    }
    public void mapWords(){
        for(int i = 0; i < tokens.length; i++){
            if(mp.containsKey(tokens[i])){
                //increment Integer
                mp.put(tokens[i], mp.get(tokens[i]) + 1);//add it to the hashmap and increment integer
            } 
            else{
                mp.put(tokens[i],1);//add it to the hashmap
            }
        }
    }
    public void printMap(){
        for(Map.Entry<String, Integer> entry : mp.entrySet()){//loop thru map to print data
            //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            textOutput.append("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
    }

I'm a bit lost actually. I googled the errors of course but nothing really good came out of it...sorry

Null pointer exception.... Uninitialised variable.
Look at the line it refers to. The only var it could be is textInput.
Why is it null?
You declare it on line 24 but you never initialise it
You may think that line 40 does that, but it just initialises a local var with the same name.

Thank JamesCherrill, yes correct, I would have thought that the constructor initialized the variable to a default state. Anyway, I've now "initialised" both textInput and textOutput, but since they are JTextArea I initialized them to empty, like so

textOutput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setText(" ");//initialize to empty string
        textOutput.setText(" ");//initialize to empty string
        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();

Trouble is, I still get the same errors, and the line that appears in the stack trace refers to line 76 now (it was 74 before) which is this stringToTest = textInput.getText();
As far as I know stringToTest is declared private String stringToTest;//holds string pasted in textarea, initialized stringToTest = "";//initialize to empty string and put to use processString(getString());//call function to split string (there is of course a getter method

public String getString(){
        return stringToTest;
    }

)
is it possible that perhaps the stringToTest variable somehow doesn't get the text that's in the textArea and therefore the functions calls inside the actionPerformed method can't process the text?

public void actionPerformed(ActionEvent event){
            stringToTest = textInput.getText();
            processString(getString());//call function to split string
            mapWords();//count words and place results in the hashmap
            printMap();//print the map values and keys in the textArea
        }//end of actionPerformed

Here is the full class again, with the amendments (this time on pastebin) http://pastebin.com/8wCe9E2S

You ignored the problem I told you about.
There are two textInput variables, declared on lines 24 and 40 in the previous code.
The first one is used throughout the class, but the second one is the one you initialise.
All the other stuff you changed will not fix that problem. You really must spend more time reading our replies carefully, thinking about them, and asking questions if there is something you still don't understand.

Sorry, I didn't mean to ignore it, more likely I didn't understand your reply.
So you're saying there are two instances of textInput: is that because the second time I prefixed it with the type JTextArea effectively shadowing the private variable? If so, sorry I didn't realize that by doing it I'd create another variable. In that case I have a duplicate of all the private variables, without realizing. I will amend.

Yes, that's exactly right.
We do try to give hints rather than solutions because that's how people learn. But if anything is too cryptic then please ask for clarification.

That's fair enough, I like the way you guys work, and yes you're right, better a hint than giving away code, my bad for misunderstanding and not spotting a silly mistake as that.
In any case, on a positive note, from now on, I will do the GUI as last thing and not as first, lesson learned. Do you guys think that for every GUI I develop I have to do a console-only version first, to get the logic right, and then only when the functionality works, redo the program as a GUI? That seems like quite a bit of overhead though. Is there any other way you recommend?
Finally, I will attempt to redo this application with a GridBagLayout, as you JamesCherrill said that that 's the most powerful and customizable layout manager and with the ones I've used I'm really not happy with the result, but this will go into a new thread.

Ok
As for gridbaglayout, yes I use it when I need exact or complex layouts, but I still use border + grid or box or flow + nested panels for simple stuff. Don't make it any more complex than it needs to be.
No, you don't need to do a console app. Write your application logic in stand-alone classes/methods then simply hard-code some test cases by calling those methods from a main with suitable data values. Keep that test code do you can run the tests again after you enhance or fix the application logic
I usually have a main method in any top level class I write, and it contains an assortment of test/demo calls for the public methods in that class. I use that to ensure its working before I try to integrate it with other classes, and for regression testing after changes. It also serves as a quick example of how to use that class!

OK, I understand, I'll try to apply those principles in the next application then.
About the GridBagLayout: the reason why I was thinking to redo this application with a GridBagLayout is because, as mentioned, I'm not satisfied with the way I display buttons and textfields
wordCount.jpg
I wanted some space between the top panel, the buttons and the bottom panel; I also wanted some padding in the JLabel, and add space outside the elements - like between the textarea and the edge of the bounding box, and I would have thought that with the GridBagLayout I could achieve all that, but if you think that I can do all that with the current layouts I've used or by rejigging the panels and the elements inside them, then I'm happy to redo it. I had a look on google a few days ago and a few people seem to say that you can use transparent borders, some other saying that the space/padding can be created by using other layoutManagers so I'm not quite sure what to do. I seem to remember testing margins (setMargin()) but it only worked inside the textarea rather than outside.
I've also read a few tutorials online, but none of them seems to be giving a definitive answer as to how to create empty space/padding around elements/panels

Edited 1 Year Ago by Violet_82

Cool, then GBL will be. I do understand what you say about not making things unnecessarily complicated though, but it will have a chance to practice :-)

Oh, I forgot, here is the final code:

/*WordCount.java
Application determines how many times a word has occurred in the text given
*/
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JScrollPane;
import java.awt.Insets;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
import java.util.StringTokenizer;
public class WordCount extends JFrame{
    private JPanel buttonsPanel;
    private JPanel topPanel;
    private JTextArea textInput;
    private JTextArea textOutput;
    private JButton processButton;
    private JButton clearButton;
    private JLabel instructions;
    private BorderLayout frameLayout;
    private BorderLayout topPanelLayout;
    private GridLayout buttonsPanelLayout;
    private String stringToTest;//holds string pasted in textarea
    private String[] tokens;//array of tokenized strings
    Map<String,Integer> mp = new HashMap<String, Integer>();//declaring a map object
    //constructor
    public WordCount(){
        super("Word count application");
        buttonsPanel = new JPanel();//holds the two buttons
        topPanel = new JPanel();//holds the textArea and jlabel
        textInput = new JTextArea(10,15);//holds the input text
        textOutput = new JTextArea(10,15);//hold the output text
        stringToTest = "";//initialize to empty string
        processButton = new JButton("Count");//action abutton
        clearButton = new JButton("Clear");//to clear textArea
        instructions = new JLabel("Copy and paste text in the below text area, click Count to count the words.\n");//holding instructions
        BorderLayout frameLayout = new BorderLayout();//for JFrame
        BorderLayout topPanelLayout = new BorderLayout();//for top level panel
        GridLayout buttonsPanelLayout = new GridLayout(1,2,5,5);//for buttons       
        setLayout(frameLayout);//set layout of Frame
        topPanel.setLayout(topPanelLayout);//set topPanel layout
        topPanel.add(instructions, BorderLayout.NORTH);//add JLabel to topPanel
        instructions.setOpaque(true);//need this to be able to change the colour
        instructions.setBackground(Color.CYAN);     
        topPanel.add(new JScrollPane(textInput), BorderLayout.CENTER);//add textInput to topPanel
        buttonsPanel.setLayout(buttonsPanelLayout);//set buttonsPanel layout
        buttonsPanel.add(processButton);//add processButton to panel
        buttonsPanel.add(clearButton);//add clearButton to panel        
        add(topPanel, BorderLayout.NORTH);//add topPanel to JFrame
        add(buttonsPanel, BorderLayout.CENTER);//add buttonsPanel to JFrame 
        add(new JScrollPane(textOutput), BorderLayout.SOUTH);//add textOutput to JFrame
        textOutput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setMargin(new Insets(5,5,5,5));//sets margins inside the element
        textInput.setText("");//initialize to empty string
        textOutput.setText("");//initialize to empty string
        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        processButton.addActionListener(handler1);
        clearButton.addActionListener(handler2);
    }//end of WordCount constructor
    public String getString(){
        return stringToTest;
    }
    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            stringToTest = textInput.getText();
            processString(getString());//call function to split string
            mapWords();//count words and place results in the hashmap
            printMap();//print the map values and keys in the textArea
        }//end of actionPerformed
    }//end of inner class
    private class ClearButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            textOutput.setText("");
            textInput.setText("");
        }//end of actionPerformed
    }//end of inner class
    public void processString(String testingString){        
        //String[] tokens = testingString.split("(?=[,.])|\\s+");
        testingString = testingString.replaceAll("[,.;:]","");//remove the characters in brackets and replace them with nothing
        tokens = testingString.split(" ");//split string using space as delimiter
        /* System.out.printf("Number of elements: %d\nTokens are \n", tokens.length);
        //print to test
        for(String token : tokens){
            System.out.println(token);
        }    */ 
    }
    public void mapWords(){
        for(int i = 0; i < tokens.length; i++){
            if(mp.containsKey(tokens[i])){
                //increment Integer
                mp.put(tokens[i], mp.get(tokens[i]) + 1);//add it to the hashmap and increment integer
            } 
            else{
                mp.put(tokens[i],1);//add it to the hashmap
            }
        }
    }
    public void printMap(){
        for(Map.Entry<String, Integer> entry : mp.entrySet()){//loop thru map to print data
            //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            textOutput.append("Key = " + entry.getKey() + ",\t Value = " + entry.getValue() + "\n");
            System.out.println("Key = " + entry.getKey() + ",\t Value = " + entry.getValue()+ "\n");//for debug purposes
        }
    }

}//end of WordCount




/*WordCountTest.java
    WordCountTest to test the class
*/
import javax.swing.JFrame;
public class WordCountTest{
    public static void main(String[] args){
        WordCount wordCount = new WordCount();
        wordCount.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        wordCount.setSize(900, 800);
        wordCount.pack();
        wordCount.setVisible(true);

    }
}//end of WordCountTest
This question has already been answered. Start a new discussion instead.