Detecting user input: Java jTextfield with DocumentListener causes erratic GUI Action

I have a larger program that one JFrame is used both for displaying program output and detecting user typing
in JTextfield controls that is processed by a DocumentListener so that if the user changes the contents of the JTextfield
the program can perform the appropriate action corresponding action to that user change. The program can also write to this JTextfield if buttons are clicked. Problem: Basically there seems to be a discrepancy between changes made in the contents of the JTextfield manually and programmatically. The update of the textfield doesn't show correctly under certain circumstances.

To illustrate the problem, here is the simplified input form:
This shows the complete JFrame, with the controls involved in the issue marked
By activating ->Board ->Get Selected Parts from the menus the string "Test" gets loaded into 'jtxtfldCompInGroup2' text field.
Then by pressing 'jbtnRditGroup2' (Edit Group) button this gets copied to 'jtxtfldGroup2_Edit', to the textfield below:
(Also note that the 'Edit Group' button is disabled at this point.)
String 'Test' is copied over from the top textfield to the one below
Now, I can manually type in the 'Test2, Test3, Test4' text into 'jtxtfldGroup2_Edit'. As I am doing this, the DocumentListener is
looking at what I am typing in the jTextfield and it will perform the appropriate action for the changed content of the
'jtxtfldGroup2_Edit' JTextfield:
Manually typing in additional characters in editable text field
Now, I can click the 'Save Group' button ('jbtnSaveNewGroup') and it will overwrite the contents of the original
top text field 'jtxtfldCompInGroup2' correctly. The DocumentListener is also working correctly at this point, I can perform
updates multiple times successfully:
Copying the hand-edited contents of bottom text field copied to the top text field
This will work multiple times correctly copying from bottom to top, and 'Edit Group' to copy from top to bottom is enabled again
but no longer working:
Now I add some text to the bottom text field that I expect to lose when I press Edit Group
Copying from the non-editable text field to the editable text field will no longer work now, the contents of the editable
text field is not changed by pressing the button:
Edit Group button action is no longer working, even though worked the first time
At this point the bottom editable text-field becomes non-functional for manual editing, save group will blank out the
top textfield instead of writing the contents:
Save button will not write text to top text field correctly (blank)
Also, the functionality if the editable text box is broken at this point, no longer can be edited manually, no matter
what you type the contents get messed up. (This works the same with the 'Clear Group' button too):
Text box is editable, but it doesn't work any more
The code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class GUI_NotUpdate extends JFrame {
    private JMenuBar menuBar1;
    private JMenu mnuTopLevel_View;
    private JMenu mnuBoard;
    private JMenuItem jmiGetSelectedParts;
    private JLabel jlblTitle;
    private JLabel jlblGroupsSelected;
    private JComboBox jcmboGroupNames;
    private JLabel jlblAddNewGroup;
    private JTextField jtxtfldGroupName;
    private JLabel jlblGroupName2;
    private JButton jbtnDeleteGroup;
    private JButton jbtnClearNewGroup;
    private JTextField jtxtfldCompInGroup1;
    private JLabel jlblCompSelInGroup1;
    private JSeparator separator1;
    private JSeparator separator2;
    private JButton jbtnEditGroup;
    private JButton jbtnSaveGroup;
    private JLabel jlblGroupName1;
    private JTextField jtxtfldCompInGroup2;
    private JLabel jlblCompSelInGroup2;
    private JButton jbtnSaveNewGroup;
    private JButton jbtnReAnnotatePCB;
    private JSeparator separator3;
    private JTextField jtxtfldGroup1_Edit;
    private JTextField jtxtfldGroup2_Edit;
    private JLabel jlblCompSelInGroup3;
    private JLabel jlblCompSelInGroup4;
    private JButton jbtnEditGroup2;
     // instantiate action listener class that is used for all the menus:
           private MenuActionListener menuActionListener = new MenuActionListener();
           // These constants will identify which of the text fields was
           // changed by the user, for the method handling document listener for
           // text areas:
           private final int  COMPSINGROUP1_FOCUSED = 1;
           private final int  COMPSINGROUP2_FOCUSED = 2;
           private int lastChangedTextFieldID = 0;
public GUI_NotUpdate() {
	    super("     Re-Annotate Screen" ); // Child window initialization
	    try {
                    // Set the look and feel for the current OS (Windows) Scheme
                } catch (Exception e) {
            }   // End of Constructor

	private void jcmboGroupNamesItemStateChanged(ItemEvent e) {
		// TODO add your code here

	private void jtxtfldGroupNameActionPerformed(ActionEvent e) {
		// TODO add your code here

	private void jbtnDeleteGroupActionPerformed(ActionEvent e) {
		System.out.println("Delete Group 1 Clicked");

	private void jbtnClearNewGroupActionPerformed(ActionEvent e) {
	    System.out.println("Clear New Group Clicked");

	private void jtxtfldCompInGroup1ActionPerformed(ActionEvent e) {
		// TODO add your code here

	private void jbtnEditGroupActionPerformed(ActionEvent e) {
	    System.out.println("Edit Group 1 Clicked");
	    // copy 'jtxtfldCompInGroup1' contents to 'jtxtfldGroup1_Edit'

	private void jbtnSaveGroupActionPerformed(ActionEvent e) {
		System.out.println("Save Group 1 Clicked");

	private void jtxtfldCompInGroup2ActionPerformed(ActionEvent e) {
		// TODO add your code here

	private void jbtnSaveNewGroupActionPerformed(ActionEvent e) {
	    System.out.println("Save Group 2 Clicked");
	   // jtxtfldGroup2_Edit.setText("");  // CANNOT BE SET PROGRAMMATICALLY!!!!

	private void jbtnReAnnotatePCBActionPerformed(ActionEvent e) {
		System.out.println("Re-Annotate PCB Clicked");

	private void jtxtfldGroup1_EditActionPerformed(ActionEvent e) {
		// TODO add your code here

	private void jbtnEditGroup2ActionPerformed(ActionEvent e) {
	    System.out.println("Edit Group 2 Clicked");
            // copy 'jtxtfldCompInGroup2' contents to 'jtxtfldGroup2_Edit'
            String text = jtxtfldCompInGroup2.getText();

	private void initComponents() {
		// JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
		menuBar1 = new JMenuBar();
		mnuTopLevel_View = new JMenu();
		mnuBoard = new JMenu();
		jmiGetSelectedParts = new JMenuItem();
		jlblTitle = new JLabel();
		jlblGroupsSelected = new JLabel();
		jcmboGroupNames = new JComboBox();
		jlblAddNewGroup = new JLabel();
		jtxtfldGroupName = new JTextField();
		jlblGroupName2 = new JLabel();
		jbtnDeleteGroup = new JButton();
		jbtnClearNewGroup = new JButton();
		jtxtfldCompInGroup1 = new JTextField();
		jlblCompSelInGroup1 = new JLabel();
		separator1 = new JSeparator();
		separator2 = new JSeparator();
		jbtnEditGroup = new JButton();
		jbtnSaveGroup = new JButton();
		jlblGroupName1 = new JLabel();
		jtxtfldCompInGroup2 = new JTextField();
		jlblCompSelInGroup2 = new JLabel();
		jbtnSaveNewGroup = new JButton();
		jbtnReAnnotatePCB = new JButton();
		separator3 = new JSeparator();
		jtxtfldGroup1_Edit = new JTextField();
		jtxtfldGroup2_Edit = new JTextField();
		jlblCompSelInGroup3 = new JLabel();
		jlblCompSelInGroup4 = new JLabel();
		jbtnEditGroup2 = new JButton();

		//======== this ========
		Container contentPane = getContentPane();
		//======== menuBar1 ========
			//======== mnuTopLevel_View ========

			//======== mnuBoard ========

				//---- jmiGetSelectedParts ----
				jmiGetSelectedParts.setText("Get Selected Parts");

		//---- jlblTitle ----
		jlblTitle.setText("Select / Edit Groups of Components for Re-Annotating PCB");
		jlblTitle.setFont(new Font("Times New Roman", Font.BOLD, 14));
		jlblTitle.setBounds(65, 5, 380, 25);

		//---- jlblGroupsSelected ----
		jlblGroupsSelected.setText("Groups Already Selected:");
		jlblGroupsSelected.setFont(new Font("Tahoma", Font.BOLD, 12));
		jlblGroupsSelected.setBounds(35, 35, 160, jlblGroupsSelected.getPreferredSize().height);

		//---- jcmboGroupNames ----
		jcmboGroupNames.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent e) {
		jcmboGroupNames.setBounds(55, 70, 385, jcmboGroupNames.getPreferredSize().height);

		//---- jlblAddNewGroup ----
		jlblAddNewGroup.setText("Save Group");
		jlblAddNewGroup.setFont(new Font("Tahoma", Font.BOLD, 12));
		jlblAddNewGroup.setBounds(35, 220, 170, jlblAddNewGroup.getPreferredSize().height);

		//---- jtxtfldGroupName ----
		jtxtfldGroupName.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jtxtfldGroupName.setBounds(55, 260, 385, jtxtfldGroupName.getPreferredSize().height);

		//---- jlblGroupName2 ----
		jlblGroupName2.setText("Group Name:");
		jlblGroupName2.setBounds(55, 245, 115, jlblGroupName2.getPreferredSize().height);

		//---- jbtnDeleteGroup ----
		jbtnDeleteGroup.setText("Delete Group");
		jbtnDeleteGroup.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnDeleteGroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnDeleteGroup.setBounds(355, 185, 130, jbtnDeleteGroup.getPreferredSize().height);

		//---- jbtnClearNewGroup ----
		jbtnClearNewGroup.setText("Clear Group");
		jbtnClearNewGroup.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnClearNewGroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnClearNewGroup.setBounds(355, 370, 130, jbtnClearNewGroup.getPreferredSize().height);

		//---- jtxtfldCompInGroup1 ----
		jtxtfldCompInGroup1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jtxtfldCompInGroup1.setBounds(15, 115, 480, jtxtfldCompInGroup1.getPreferredSize().height);

		//---- jlblCompSelInGroup1 ----
		jlblCompSelInGroup1.setText("Components Currently Saved in Group:");
		jlblCompSelInGroup1.setBounds(20, 100, 195, jlblCompSelInGroup1.getPreferredSize().height);
		separator1.setBounds(15, 145, separator1.getPreferredSize().width, 2);
		separator2.setBounds(20, 215, 465, 10);

		//---- jbtnEditGroup ----
		jbtnEditGroup.setText("Edit Group");
		jbtnEditGroup.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnEditGroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnEditGroup.setBounds(35, 185, 130, jbtnEditGroup.getPreferredSize().height);

		//---- jbtnSaveGroup ----
		jbtnSaveGroup.setText("Save Group");
		jbtnSaveGroup.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnSaveGroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnSaveGroup.setBounds(195, 185, 130, jbtnSaveGroup.getPreferredSize().height);

		//---- jlblGroupName1 ----
		jlblGroupName1.setText("Group Name:");
		jlblGroupName1.setBounds(new Rectangle(new Point(55, 55), jlblGroupName1.getPreferredSize()));

		//---- jtxtfldCompInGroup2 ----
		jtxtfldCompInGroup2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jtxtfldCompInGroup2.setBounds(15, 300, 475, 20);

		//---- jlblCompSelInGroup2 ----
		jlblCompSelInGroup2.setText("Components Currently Saved in Group:");
		jlblCompSelInGroup2.setBounds(15, 285, 210, 14);

		//---- jbtnClearGroup ----
		jbtnSaveNewGroup.setText("Save Group");
		jbtnSaveNewGroup.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnSaveNewGroup.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnSaveNewGroup.setBounds(195, 370, 130, jbtnSaveNewGroup.getPreferredSize().height);

		//---- jbtnReAnnotatePCB ----
		jbtnReAnnotatePCB.setText("Re-Annotate PCB");
		jbtnReAnnotatePCB.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnReAnnotatePCB.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnReAnnotatePCB.setBounds(185, 425, 143, jbtnReAnnotatePCB.getPreferredSize().height);
		separator3.setBounds(20, 405, 465, 10);

		//---- jtxtfldGroup1_Edit ----
		jtxtfldGroup1_Edit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jtxtfldGroup1_Edit.setBounds(15, 155, 480, 20);

		//---- jtxtfldGroup2_Edit ----
		jtxtfldGroup2_Edit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jtxtfldGroup2_Edit.setBounds(15, 340, 475, jtxtfldGroup2_Edit.getPreferredSize().height);

		//---- jlblCompSelInGroup3 ----
		jlblCompSelInGroup3.setText(" Edit Components in Group:");
		jlblCompSelInGroup3.setBounds(15, 140, 195, 14);

		//---- jlblCompSelInGroup4 ----
		jlblCompSelInGroup4.setText(" Edit Components in Group:");
		jlblCompSelInGroup4.setBounds(15, 325, 195, 14);

		//---- jbtnEditGroup2 ----
		jbtnEditGroup2.setText("Edit Group");
		jbtnEditGroup2.setFont(new Font("Tahoma", Font.BOLD, 11));
		jbtnEditGroup2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
		jbtnEditGroup2.setBounds(35, 370, 130, 23);

		{ // compute preferred size
			Dimension preferredSize = new Dimension();
			for(int i = 0; i < contentPane.getComponentCount(); i++) {
				Rectangle bounds = contentPane.getComponent(i).getBounds();
				preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
				preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
			Insets insets = contentPane.getInsets();
			preferredSize.width += insets.right;
			preferredSize.height += insets.bottom;
	    // Add a listener to the underlying Document object for JTextField, which is automatically created.   
	                        // Listen for changes in the text entered in all the text fields:
	                        jtxtfldGroup1_Edit.getDocument().addDocumentListener(new DocumentListener() {
	                          public void changedUpdate(DocumentEvent e) {
	                          public void removeUpdate(DocumentEvent e) {
	                          public void insertUpdate(DocumentEvent e) {
	                        jtxtfldGroup2_Edit.getDocument().addDocumentListener(new DocumentListener() {
	                          public void changedUpdate(DocumentEvent e) {
	                          public void removeUpdate(DocumentEvent e) {
	                          public void insertUpdate(DocumentEvent e) {
	}   // End of component initialization
    // The change is detected in EITHER of the MONITORED textfields, modify selection in the PCB accortdingly: 
    // Keep track of which textfield was changed last time. If the textfield ID changes clear board
    // and see what the last character is comma or space, if yes then update selection.
    public void changeDetected(int textFieldRefNumber) {
                   System.out.println("Change Detected: " + textFieldRefNumber);

                   String updatedText = "";
                   // when the change is detected look at the last character in textfield changed.
                   // if the last character is a space or comma update selection in PCB
                   if (textFieldRefNumber == COMPSINGROUP1_FOCUSED ){
                       // get the text field contents, if last character is space or comma select parts:
                       updatedText = jtxtfldGroup1_Edit.getText();
                       // get the other text field contents,
                       updatedText = jtxtfldGroup2_Edit.getText();
               String lastChar = updatedText.substring(updatedText.length()-1, updatedText.length());
                       //  if last character is space or comma select parts:
                   // Save last changed textfield reference
                   lastChangedTextFieldID = textFieldRefNumber;
    public static void main(String[] args) {
                    GUI_NotUpdate gUI_NotUpdate = new GUI_NotUpdate();
   // MENU ACTION LISTENER - inner class actionlistener for all menus:
   private class MenuActionListener implements ActionListener {
           public MenuActionListener(){   
                   public void actionPerformed(ActionEvent e) {

                            String actionCommand = e.getActionCommand();
                           if (actionCommand == "Save New Selection") {
                               System.out.println("Save New Selection Selected");
                               // casconMainScreen.clearSelectionInPCB();
                           if (actionCommand == "Clear Group") {
                               System.out.println("Clear Group Selected");
                           if (actionCommand == "Get Selected Parts") {
   }        // End of inner class MenuActionListener
}  // End of Class

Open in new window

What is happening here, and what can I do about it?
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I am not sure if this is your entire problem, but I noticed some NPEs when running the code, which I may have fixed, somewhere roughly between these line numbers :

432 through 453.

the code amendments I made are :

String updatedText = "";
				   String lastChar=null;
                   // when the change is detected look at the last character in textfield changed.
                   // if the last character is a space or comma update selection in PCB
                   if (textFieldRefNumber == COMPSINGROUP1_FOCUSED ){
                       // get the text field contents, if last character is space or comma select parts:
                       updatedText = jtxtfldGroup1_Edit.getText();
                       // get the other text field contents,
                       updatedText = jtxtfldGroup2_Edit.getText();
               /*String*/ lastChar = updatedText.substring(updatedText.length()-1, updatedText.length());
                       //  if last character is space or comma select parts:

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
AttilaBAuthor Commented:
Well, your code actually works as expected. So this IS the solution. I could not make it fail when I tried, with any sequence of actions on the GUI.

You are declaring and initializing String lastChar at the beginning, outside the block.
I do it just right before I use it, but I initialize it every time before taking the substring, anyway.

I don't understand why my code causes the problems I am experiencing at run-time only, and yours doesn't.

What does NPEs mean?
NPE - NullPpointerException. (Acutally I didn't think you had runtime errors from your question, but maybe I missed something).

Well the lastChar String should be tested, shouldn't it? Because if it is null, then there's no point calling equals() on it. I don't know the likely null and non-null conditions of your String vars without going over the whole code, but I'd say that unless you are 100% sure some String can never return null, then a test for null comes in handy. ;)
Exploring SharePoint 2016

Explore SharePoint 2016, the web-based, collaborative platform that integrates with Microsoft Office to provide intranets, secure document management, and collaboration so you can develop your online and offline capabilities.

AttilaBAuthor Commented:
Thanks for your help and explanation!
By the way -

lastChar = updatedText.substring(updatedText.length()-1, updatedText.length());

Open in new window

can be simply

lastChar = updatedText.substring(updatedText.length()-1);

Open in new window

... and because you test "updatedText" for a length more than zero, if it IS zero, then lastChar will fail . . . so you might want to give that whole passage there some more thought.
Added one last comment to my previous. Ciao.
AttilaBAuthor Commented:
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.