Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 6 of 6

Thread: Is there an easier way to do this?

  1. #1
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    161
    My Mood
    Stressed
    Thanks
    14
    Thanked 25 Times in 25 Posts

    Default Is there an easier way to do this?

    I'm trying to implement the Find function of a Find/Replace for a JTextArea. I have a way, I think, to do the find. However, it seems inefficient but I can't think of any other way without lots of variables. I used an ArrayList to keep track of where everything was so I could do findUp() and findDown() and all I needed was the ArrayList and the currentIndex of where I am in that ArrayList. It should work, but seems poor. Especially as I will likely have to recreate the ArrayList if the document gets changed while my find dialog (not shown here as it's not the issue) is up as the dialog isn't modal (Hence the DocumentListener, not implemented yet, to fix that possibility.) I also was wondering how I could handle a change of the search term without having to recreate a new Finder object in my Find/Replace dialog. (I'd need to change foundString to something else, but still, I'd need to recreate the ArrayList.)

    As for how to do a find without using match case, I can only think of String.split(" ") and using equals ignore case. Either way, this seems tricky and I was wondering there was a better way without having to keep tracks of dozens of variables.


    Here's what I have so far. (Note, JTitledTextArea is a subclass of JTextArea that has a title at the top using a TitledBorder. It is pretty similar to JTextArea.)

    package gui.utilities;
     
    import components.JTitledTextArea;
    import java.awt.Color;
    import javax.swing.JOptionPane;
    import java.util.ArrayList;
    import javax.swing.event.DocumentListener;
    import javax.swing.event.DocumentEvent;
     
     
    public class Finder implements DocumentListener
    {
     
     
       private String mainString;
     
     
       private ArrayList<Integer> matches;
       private ArrayList<Integer> ignoreCaseMatches;
       private String foundString;
       private JTitledTextArea jtta;
       private int currentIndex;
     
     
       public Finder(JTitledTextArea jtta, String foundString)
       {
          this.jtta = jtta;
          this.foundString = foundString;
          this.mainString = jtta.getText();
     
          currentIndex = 0;
          matches = new ArrayList<Integer>();
          ignoreCaseMatches = new ArrayList<Integer>();
     
     
     
     
          int length = foundString.length();
     
          int foundAt = 0;
          int indexOf = 0;
     
     
          while (foundAt != -1)
          {
     
     
             foundAt = mainString.indexOf(foundString, indexOf);
     
             if (foundAt != -1)
             {
     
                matches.add(foundAt);
     
                indexOf = foundAt + length;
     
     
             }
     
     
     
     
          }
     
     
          jtta.getDocument().addDocumentListener(this);
     
     
     
       }
     
     
       public void findDown()
       {
     
          if (matches.size() == 0 || currentIndex == matches.size()-1)
          {
             JOptionPane.showMessageDialog(null, "Could not find the item '" + foundString + "'.", "Not Found", JOptionPane.INFORMATION_MESSAGE);
             return;
     
          }
     
          else
          {
     
     
             jtta.setSelectionStart(matches.get(currentIndex + 1));
     
             jtta.setSelectionEnd(matches.get(currentIndex + 1) + foundString.length());
     
             currentIndex++;
     
     
          }
     
     
     
     
     
     
       }
     
     
       public void findUp()
       {
     
     
          if (matches.size() == 0 || currentIndex == 0)
          {
             JOptionPane.showMessageDialog(null, "Could not find the item '" + foundString + "'.", "Not Found", JOptionPane.INFORMATION_MESSAGE);
             return;
     
          }
     
          else
          {
     
     
             jtta.setSelectionStart(matches.get(currentIndex -1));
     
             jtta.setSelectionEnd(matches.get(currentIndex - 1) + foundString.length());
     
             currentIndex--;
     
     
          }
     
     
       }
     
     
       public void changedUpdate(DocumentEvent e)
       {
     
     
       }
     
       public void insertUpdate(DocumentEvent e)
       {
     
     
       }
     
       public void removeUpdate(DocumentEvent e)
       {
     
     
       }
     
     
     
     
     
     
    }


  2. #2
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    161
    My Mood
    Stressed
    Thanks
    14
    Thanked 25 Times in 25 Posts

    Default Re: Is there an easier way to do this?

    Ok, I could do findDown() without the ArrayList but I'd still need to know where my last find was to get the index to use the substring method and use that index + the length of the search term and it would work.

    However, to findUp(), I would need to move backwards. I think I can use lastIndexOf() but I'd still need to know where I am.

    I could possibly use the cursor position, assuming that the cursor was at the start of the highlighted word, to get where I'm at.


    However, for the instances where I would want to findDownIgnoreCase() or findUpIgnoreCase() where I don't match case, I am a bit confused there.

    lastIndexOf() and substring() check the String passed to it on the equals() basis basically, not the equalsIgnoreCase() basis. regionMatches() won't work either. I cannot find a way to do this, yet I know it has to be done somehow.

    Also, it is possible that the user could, by checking or unchecking the checkbox for "Match Case" or by changing the search term or even editing the text document (the find/replace dialog isn't modal) that things could be altered and have dire consequences.

  3. #3
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: Is there an easier way to do this?

    Would it be possible to use the Matcher (Matcher (Java Platform SE 7 )) and Pattern class instead?
    I'm not 100% sure of exact implementation for your case, but the methods there alone should sold a handful of your issues.

    As for the findUp(), why not just findDown() and then reverse the list? That would be the short and easy way.

    As for the ignore case ones, just call the String.toUpperCase() or String.toLowerCase() on your document and your matcher String and just compare normally. That would also be the short and easy way.

    As for altering the data, that is something you'll have to test and see.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  4. The Following User Says Thank You to aussiemcgr For This Useful Post:

    GoodbyeWorld (October 27th, 2013)

  5. #4
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    161
    My Mood
    Stressed
    Thanks
    14
    Thanked 25 Times in 25 Posts

    Default Re: Is there an easier way to do this?

    Quote Originally Posted by aussiemcgr View Post
    Would it be possible to use the Matcher (Matcher (Java Platform SE 7 )) and Pattern class instead?
    I'm not 100% sure of exact implementation for your case, but the methods there alone should sold a handful of your issues.

    As for the findUp(), why not just findDown() and then reverse the list? That would be the short and easy way.

    As for the ignore case ones, just call the String.toUpperCase() or String.toLowerCase() on your document and your matcher String and just compare normally. That would also be the short and easy way.

    As for altering the data, that is something you'll have to test and see.
    I abandoned the ArrayList implementation.

    My new idea is to use the indexOf() for findDown() and lastIndexOf() for findUp() from the String class.

    As for the case matching, I had an idea, though it might still be inefficient. I was going to for findDownIgnoreCase() or whatever I'm going to call it, start at the caret position and just go through each char each compare and, if it finds a match of the first char, entire some loop to keep checking and stop the loop if it not a complete match, and use the equalsIgnoreCase with the String.valueOf(char). I could do the do the thing in reverse starting at the caret position and moving backwards for findUpIgnoreCase().

    However, one of the rubs seems to that I fear that I'm not moving the caret when I call the setSelectionStart() and setSelectionEnd() (though I can change that, of course.) However, the real drawback is that, maybe, I am losing the caret altogether as I might be losing focus when I go from the JTextArea to the find window and the find Text field.

    I am getting weird, sometimes varying errors, with what I'm trying now for findDown(). It sometimes says I'm referring to index -128 (how it's doing that is anyone's guess. Other times, though I definitely have the search term in there, and often many times, it can't find the term and is returning that it can't find it.

    package gui.utilities;
     
    import components.JTitledTextArea;
    import java.awt.Color;
    import javax.swing.JOptionPane;
    import java.util.ArrayList;
    import javax.swing.event.DocumentListener;
    import javax.swing.event.DocumentEvent;
     
     
    public class Finder 
    {
     
     
       private String mainString;
     
     
     
       private String foundString;
       private JTitledTextArea jtta;
       private int length;
     
     
     
       public Finder(JTitledTextArea jtta, String foundString)
       {
          this.jtta = jtta;
          this.foundString = foundString;
          this.mainString = jtta.getText();
     
     
     
     
     
     
     
          this.length = foundString.length();
     
     
     
     
     
     
       }
     
     
       public void findDown()
       {
     
          int pos = jtta.getCaretPosition();
          System.out.println("What is pos:  " + pos);
     
          String sub  = mainString.substring(pos);
          System.out.println(sub);
          System.out.println("Length: " + length);
          if (mainString.length() ==0 || length == 0 ||   !(sub.contains(foundString)))
          {
     
     
             JOptionPane.showMessageDialog(null, "The search item '" + foundString + "' could not be found.", "Not found.", JOptionPane.INFORMATION_MESSAGE);
             return;
     
     
     
     
          }
     
     
          else
          {
     
     
             int start = mainString.indexOf(foundString, pos);
     
             int stop = start + length;
     
             jtta.setSelectionStart(start);
             jtta.setSelectionEnd(stop);
             jtta.setCaretPosition(stop);
     
     
     
     
     
     
     
     
     
          }
     
     
     
     
     
       }
     
     
       public void findUp()
       {
     
     
     
     
     
       }
     
     
     
       public void setFoundString(final String foundString)
       {
          this.foundString = foundString;
     
          this.length = foundString.length();
       }
     
     
     
     
     
     
     
     
     
    }


    Here is what is going on in the Find part of the GUI

     private class FindPanel extends JPanel
       {
     
          private javax.swing.JTextField findField;
          private JPanel topPanel;
          private JPanel bottomPanel;
          private JLabel findLabel;
          private JButton findNext, cancel;
          private Finder find;
          private static final int NORMAL_UP = 1;
          private static final int NORMAL_DOWN = -1;
          private static final int CASELESS_UP = 2;
          private static final int CASELESS_DOWN = -2;
          private JRadioButton findUp, findDown;
          private JCheckBox ignoreCase;
          private boolean up;
     
     
          public FindPanel()
          {
             setVisible(true);
             findLabel = new JLabel("<html><B> Find: </B></html>");
             up = false;
             findField = new javax.swing.JTextField(20);
             ComponentFormatter.addPopupMenu(findField);
             topPanel = new JPanel();
             setLayout(new BorderLayout());
             topPanel.setLayout(new java.awt.FlowLayout());
             topPanel. setBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK, 1, true));
             topPanel.add(findLabel);
             topPanel.add(findField);
             bottomPanel = new JPanel();
     
             findNext = new JButton("Find Next");
             cancel = new JButton("Cancel");
             bottomPanel.setLayout(new java.awt.FlowLayout());
             bottomPanel. setBorder(BorderFactory.createLineBorder(java.awt.Color.BLACK, 1, true));
     
             JPanel rightPanel = new JPanel();
             rightPanel.setLayout(new java.awt.FlowLayout());
     
             rightPanel.add(findNext);
             rightPanel.add(cancel);
             findUp = new JRadioButton("Find up");
             findDown = new JRadioButton("Find down");
     
             ButtonGroup bg = new ButtonGroup();
             bg.add(findUp);
             bg.add(findDown);
             ignoreCase = new JCheckBox("Ignore case");
     
             bottomPanel.add(findUp);
             bottomPanel.add(findDown);
             bottomPanel.add(ignoreCase);
     
     
             add(topPanel, BorderLayout.WEST);
             add(bottomPanel, BorderLayout.SOUTH);
             add(rightPanel, BorderLayout.EAST);
     
     
             find = new Finder(ta, findField.getText());
             findDown.setSelected(true);
             findNext.setEnabled(false);
     
             findField.getDocument().addDocumentListener(
                   new DocumentListener() {
     
                      public void changedUpdate(DocumentEvent e)
                      {
                         findNext.setEnabled(true);
                         find.setFoundString(findField.getText());
     
                      }
     
                      public void insertUpdate(DocumentEvent e)
                      {
                         findNext.setEnabled(true);
                         find.setFoundString(findField.getText());
                      }
     
                      public void removeUpdate(DocumentEvent e)
                      {
                         findNext.setEnabled(true);
                         find.setFoundString(findField.getText());
     
                      }
     
     
                   });
     
     
     
             findNext.addActionListener(
                   new ActionListener() {
     
                      public void actionPerformed(ActionEvent e)
                      {
     
                         String foundString = findField.getText();
                         find.setFoundString(foundString);
     
                         if (up == false && !ignoreCase.isSelected())
                            find.findDown();
     
     
                      }});
     
     
     
     
     
     
     
     
     
          }
     
     
     
     
       }

    (Note: FindPanel is part of a bigger class called FindReplace, hence why it is private.)

    It either can't find the stuff even if it's there, or, if for some reason I select a bunch of text or have it selected and do the find, it suddenly acts like my String index is negative and throws a StringIndexOutOfBoundsException.

    I think I should not let it worry about multiple positions being selected (or at least try/catch it away). But why isn't it finding anything even if it's there?


    Note, I could tell it to add some fancy document listener to the JTextArea and tell it to update the value of mainString if the actual document gets edited while the dialog, which, like the one for Windows Notepad, isn't modal.

  6. #5
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: Is there an easier way to do this?

    You could lock it while it is searching. Set: JTextArea.setEditable(false); while the find is activated, and then set it back to JTextArea.setEditable(true);
    Then the user can't edit it.

    For your errors, you'll just have to add more print statements to find out what is happening. It is difficult for people on this forum to debug runtime GUI issues. If you are familiar with unit testing, this might be a good candidate for that.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  7. #6
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    161
    My Mood
    Stressed
    Thanks
    14
    Thanked 25 Times in 25 Posts

    Default Re: Is there an easier way to do this?

    Quote Originally Posted by aussiemcgr View Post
    You could lock it while it is searching. Set: JTextArea.setEditable(false); while the find is activated, and then set it back to JTextArea.setEditable(true);
    Then the user can't edit it.

    For your errors, you'll just have to add more print statements to find out what is happening. It is difficult for people on this forum to debug runtime GUI issues. If you are familiar with unit testing, this might be a good candidate for that.
    I do already have some printlns and they aren't showing the problem. In fact, they are, with the ones I've got so far, showing that it is reading it in and everything as it should be.

    (Also, Windows notepad can somehow manage to do this with the document still able to be edited. I think a DocumentListener added to the JTextArea passed as a param should do the trick for that.)


    Also, I found that I didn't need setCaretPosition as the setSelectionStart() or setSelectionEnd(0 already does it for me.

    --- Update ---

    My findDown() is now working but my findUp() is only finding the first term (I fear it may be halting at spaces or something or else just is plain buggy. If I move the cursor, then it finds the right spot, though still is buggy. I had found an issue where I had kept using it to find the last String that matched in the main String, hence, why it kept staying at the same spot. However, even after fixing it to now look for the last String that matches in the substring, and using some calculations to change the value of the String and stuff, the problem is STILL happening.)

    package gui.utilities;
     
    import components.JTitledTextArea;
    import java.awt.Color;
    import javax.swing.JOptionPane;
    import java.util.ArrayList;
    import javax.swing.event.DocumentListener;
    import javax.swing.event.DocumentEvent;
     
     
    public class Finder 
    {
     
     
       private String mainString;
     
     
     
       private String foundString;
       private JTitledTextArea jtta;
       private int length;
       private String sub;
     
     
     
       public Finder(JTitledTextArea jtta, String foundString)
       {
          this.jtta = jtta;
          this.foundString = foundString;
          this.mainString = jtta.getText();
     
     
     
     
     
     
     
          this.length = foundString.length();
     
     
     
     
     
     
       }
     
     
       public void findDown()
       {
     
          int pos = jtta.getCaretPosition();
     
          sub  = mainString.substring(pos);
     
          if (!(sub.contains(foundString)))
          {
     
     
             JOptionPane.showMessageDialog(null, "The search item '" + foundString + "' could not be found.", "Not found.", JOptionPane.INFORMATION_MESSAGE);
             return;
     
     
     
     
          }
     
     
          else
          {
     
     
     
             int start = mainString.indexOf(foundString, pos);
     
             int stop = start + length;            
             jtta.setSelectionStart(start);
             jtta.setSelectionEnd(stop);
             //jtta.setCaretPosition(stop);
     
     
     
     
     
     
     
     
     
          }
     
     
     
     
     
       }
     
     
       public void findUp()
       {
     
          int pos = jtta.getCaretPosition();
     
          sub  = mainString.substring(0, pos);
     
          if (!(sub.contains(foundString)))
          {
     
     
             JOptionPane.showMessageDialog(null, "The search item '" + foundString + "' could not be found.", "Not found.", JOptionPane.INFORMATION_MESSAGE);
             return;
     
     
     
     
          }
     
     
          else
          {
     
     
     
             int start2 = sub.lastIndexOf(foundString, pos);
             int start1 = mainString.indexOf(sub);
             int start = start2 + start1;
     
             int stop = start + length;            
             jtta.setSelectionStart(start);
             jtta.setSelectionEnd(stop);
                         //jtta.setCaretPosition(stop);
     
     
     
     
     
     
     
     
     
          }
     
     
     
     
       }
     
     
     
       public void setFoundString(final String foundString)
       {
          this.foundString = foundString;
     
          this.length = foundString.length();
       }
     
     
     
     
     
     
     
     
     
    }


    (Note: Should I have kept the String object "sub" local as I could get away with in findDown() or was I right to make it a class variable?)

Similar Threads

  1. Is there an easier way for creating shape parameters?
    By jRele in forum AWT / Java Swing
    Replies: 0
    Last Post: September 23rd, 2013, 03:38 AM
  2. Replies: 4
    Last Post: February 1st, 2013, 09:23 AM
  3. Base Changing - Is there an easier method?
    By Staticity in forum Algorithms & Recursion
    Replies: 3
    Last Post: October 2nd, 2011, 05:25 PM
  4. Beginner Question Here (Trying to make things easier)
    By beer-in-box in forum AWT / Java Swing
    Replies: 2
    Last Post: June 1st, 2011, 10:48 AM
  5. How much easier is Java compared to C++
    By Psychotron in forum Java Theory & Questions
    Replies: 6
    Last Post: May 24th, 2011, 12:15 PM