Refreshing contents of a JComboBox

What I have written (with some help from a few of the forum members here) is a JComboBox which gets its string list from a txt file.

Now, under that JComboBox, I have an “edit” button, which adds items to this text file. The problem is that I need to reload/re-read the txt file so that the JComboBox is updated and the new addition is made viewable. The trick is I want to do this without destroying and recreating the window. Any ideas? I’ve exhausted what little I know.

Sorry for the lenght of code. I have highlighted the places that pertain to the main problem.

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

public class data_entry extends JFrame{

    private String govt_name_selection = "";

    //which ComboBox to refresh
    [color=blue]private static String edit_button_pressed = "";[/color]

    public void data_entry() {

    //---start govt_dept_dept panel----

        //Govt_name DDM (Drop Down Menu)
        JLabel govt_nameL = new JLabel("Government Name:");

        [color=blue]JComboBox govt_nameCB = new JComboBox(open_dropdownlist("F:\\\\DDM_govt_name.txt"));[/color]
        govt_nameCBactn actn_govt_nameCB = new govt_nameCBactn();
        govt_nameCB.addActionListener([color=blue]actn_govt_nameCB[/color]);

        JButton govt_editB = new JButton("Edit");
        govt_editBactn actn_govt_editB = new govt_editBactn();
        govt_editB.addActionListener(actn_govt_editB);

        JPanel govt_editBP = new JPanel();
        govt_editBP.setLayout(new FlowLayout());
        govt_editBP.add(govt_editB);

        JPanel govtP = new JPanel();
        govtP.setLayout(new BorderLayout());
        govtP.add(govt_nameL, BorderLayout.NORTH);
        govtP.add(govt_nameCB, BorderLayout.CENTER);
        govtP.add(govt_editBP, BorderLayout.SOUTH);

    JPanel govt_dept_unitP = new JPanel();
    govt_dept_unitP.setLayout(new FlowLayout());
    govt_dept_unitP.add(govtP);
    //----end govt_dept_unit panel----

        //main container
        Container pane = getContentPane();
        pane.setLayout(new BorderLayout());
        pane.add(govt_dept_unitP, BorderLayout.CENTER);

    }




    //----start drop down menu string list template------
    public Object[] open_dropdownlist(String dir_path){
        java.util.List list = new ArrayList();
        try {
            String line = "";

            BufferedReader in = new BufferedReader(new FileReader(dir_path));
            while((line = in.readLine()) != null){
                list.add(line);
            }
            in.close();
        }

        catch(IOException ioeRef) {
                System.out.println("Exception " + ioeRef.toString());
                JOptionPane.showConfirmDialog(null, "Drop down menu database not found.", "Program Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
        }

        return list.toArray(new String[]{});
    }
    //----end drop down menus string list template------


    //-----start drop down menu actions-----

    //govt name action
    private class govt_nameCBactn implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                //grabs CB selection
                JComboBox box = (JComboBox)e.getSource();
                String CB_name = (String)box.getSelectedItem();
                govt_name_selection = make_CB_selection(CB_name, "F:\\\\DDM_govt_name.txt");
            }
    }


    //set JComboBox value (template)
    //first entry in drop down menu txt file is the label name, which = "";
    private String make_CB_selection(String CB_name, String dir_path){
        String line = "";
        String matched_line = "";
            try{
                BufferedReader infile = new BufferedReader(new FileReader(dir_path));
                    line = infile.readLine();
                    while((line = infile.readLine()) != null){
                        //if match found between line read from file and CB selection
                        if (line.equalsIgnoreCase(CB_name)){
                            matched_line = line;
                        }
                    }
                    infile.close();
                }

                catch(IOException ioeRef) {
                        System.out.println("Exception " + ioeRef.toString());
                        JOptionPane.showConfirmDialog(null, "Error: match for " + dir_path + " not found in database.", "Program Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
                }

                return matched_line;

            }

    //----end drop down menu actions-----



    //-----start drop down edit buttons-----

    private class [color=blue]govt_editBactn[/color] implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                DDM_edit_button edit = new DDM_edit_button();
                edit.DDM_edit_button("F:\\\\DDM_govt_name.txt");
                edit.setTitle("Edit Government Name List");
                edit.setSize(380, 140);
                edit.setVisible(true);

                [color=blue]//which CB list to refresh
                edit_button_pressed = "govt_nameCB";[/color]


            }
    }


    //-----end drop down edit buttons-----

    [color=blue]//----redraw drop down list
    public void redrawlist(String dir_path){
        if(edit_button_pressed.equalsIgnoreCase("govt_nameCB")){
            JComboBox govt_nameCB = new JComboBox(open_dropdownlist("F:\\\\DDM_govt_name.txt"));
        }
        else{
            JOptionPane.showConfirmDialog(null, "Error reloading dropdown menu" + edit_button_pressed + ".  Please logout and log back in.", "Program Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
        }
    }[/color]

}



import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

public class DDM_edit_button extends JFrame implements ActionListener{

    private JTextField new_entryTF = new JTextField(30);
    private String dir_path = "";


    public void DDM_edit_button(String dir_pathIN){
        dir_path = dir_pathIN;
        //close this window
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        //text field
        JPanel new_entryTFP = new JPanel();
        new_entryTFP.setLayout(new FlowLayout());
        new_entryTFP.add(new_entryTF);

        //button
        JButton new_entryB = new JButton("Add Entry");
        new_entryB.addActionListener(this);
        JButton close = new JButton("Close");
        close.addActionListener(this);
        JPanel new_entryBP = new JPanel();
        new_entryBP.setLayout(new FlowLayout());
        new_entryBP.add(new_entryB);
        new_entryBP.add(close);


        JPanel mainP = new JPanel();
        mainP.setLayout(new BorderLayout());
        mainP.add(new_entryTFP, BorderLayout.CENTER);
        mainP.add(new_entryBP, BorderLayout.SOUTH);

        Container pane = getContentPane();
        pane.setLayout(new FlowLayout());
        pane.add(mainP);
    }

    public void actionPerformed(ActionEvent e) {
        if(e.getActionCommand().equals("Add Entry")){
            String entry = "";
            entry = new_entryTF.getText();
            try {
                boolean entry_exists = false;
                BufferedReader infile = new BufferedReader(new FileReader(dir_path));
                String line;

                if(entry.equalsIgnoreCase(""))
                    JOptionPane.showConfirmDialog(null, "Please input an entry.", "Entry Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
                    else{
                        while((line = infile.readLine()) != null){
                            if (line.equalsIgnoreCase(entry)){
                                entry_exists=true;
                            }
                        }
                        infile.close();
                    }


                if (!entry_exists){
                    //write entry to file
                    FileWriter outfile = new FileWriter(dir_path, true);
                    outfile.write(entry + "\
");
                    outfile.close();

                    //confirm message
                    JOptionPane.showConfirmDialog(null, "The entry has been successfully added.", "User Added", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE);

                    //reset TF
                    entry = "";
                    new_entryTF.setText("");

                    [color=blue]//redraw DDM
                    data_entry redrawDDM = new data_entry();
                    redrawDDM.data_entry();
                    redrawDDM.redrawlist(dir_path);[/color]
                }
                else{
                    JOptionPane.showConfirmDialog(null, "Entry already exists.", "Entry Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
                }
            } //end try

            catch(IOException ioeRef) {
                        System.out.println("Exception " + ioeRef.toString());
                        JOptionPane.showConfirmDialog(null, "Error: match for " + dir_path + " not found in database.", "Program Error", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE);
                        dispose();
                    }
        }//end add entry button

        if(e.getActionCommand().equals("Close"))
            dispose();
    }//end actionlistener

}

I hope this is clear. If you have anything you’re confused on, let me know. I’m stumped on this problem.

[edit]: For clarification, the data_entry class is called from a main class, and the DMM_edit_button class is called from the data_entry class in the govt_editBactn method.

It seems you’re trying to have the data maintain the interface, when it really should be the other way around.

In my line of thinking, the combo box presents the file to the user and is the user’s interface for editing the file. Below is an example of this in action.

points of interest:
1-MyCombo extends JComboBox to add a file association and methods to operate on it.

2-MyCombo also implements the ActionListener interface and adds itself as a listener to handle user edit requests, handled in the actionPerformed method.

3-actionPerformed simply determines if the action was a selection change or not, then adds the edited entry to the list and rewrites the file based on the current contents of the combo box.

4-the addWindowListener code comes in handy for testing.


import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class JComboTest {
  public static void main( String[] args ) {
    new JComboTest();
  }

  public JComboTest() {
    JFrame frame = new JFrame();
    frame.addWindowListener( new WindowAdapter() {
      public void windowDeactivated( WindowEvent e ) {
        System.exit(0);
      }
    } );
    frame.getContentPane().add( new MyCombo( "input_1.log" ) );
    frame.pack();
    frame.show();
  }
}

class MyCombo extends JComboBox implements ActionListener {
  private String filename;

  public MyCombo( String filename ) {
    super( getVector( filename ) );
    this.filename = filename;
    addActionListener( this );
    setEditable( true );
  }

  private static synchronized Vector getVector( String filename ) {
    BufferedReader in = null;
    Vector vector = new Vector();
    try {
      in = new BufferedReader( new FileReader( new File( filename ) ) );
      String line = null;
      while( ( line = in.readLine() ) != null  ) {
        vector.add( line );
      }
    } catch( IOException ioe ) {
      ioe.printStackTrace();
    } finally {
      try { in.close(); } catch( IOException ioe ) { ioe.printStackTrace(); }
    }
    return vector;
  }

  public void actionPerformed( ActionEvent e ) {
    if( !"comboBoxChanged".equals( e.getActionCommand() ) ) {
      addItem( e.getActionCommand() );
      rewriteFile();
    }
  }

  public void rewriteFile() {
    PrintWriter out = null;
    try {
      out = new PrintWriter( new FileWriter( new File( filename ) ) );
      for( int i = 0; i < getItemCount(); ++i ) {
        out.println( getItemAt( i ) );
      }
    } catch( IOException ioe ) {
      ioe.printStackTrace();
    } finally {
      out.close();
    }
  }
}

hth

Ok, I’ve been messing around with the code for a few days, but can’t get the results I want.

Having a seperate pop-up window for the drop-down menu just does not work out for this program. This program is going to be a form (of sorts) and I need everything in one window.

Second, I wanted to avoid using setEditable(true);. The reason for the edit button is so users can add entries, and it will look for duplicates and alert the user that what they are trying to put in is already there.

Thrid, this program will have different levels of users (ie admin and guest), so right now what I’m doing is writing everything for full access, and later taking administrative features out. In this case, all I would have to do is remove the edit button and not worry about rewriting anything.

Now that I’ve throughly confused you, is there a way to reassign the value of the JComboBox govt_nameCB in the data_entry class?

The code was just a down-n-dirty proof of concept.

You could, if you wish, add MyCombo directly to your existing interface with something like:

panel.add( new MyCombo( “some filename”) );

just put MyCombo in it’s own file, make it public and give it the proper package statement, if applicable.

setEditable() - It doesn’t have to be editable to be editable :wink:

What I mean by that is setEditable( true ) allows the user to edit the entries, but as the programer, you have the ability to edit, add and remove the entries whether or not it is editable by the user.

To accomplish what you want with the user levels, you can:
a) create a panel that has a combo box, text box and button that all work together to allow the user, of appropriate level, to add, edit and remove the entries, the changes of which get written out to the file. User doesn’t have proper access? don’t display the editing tools (like you said) [make that 2 buttons, one to save edits and new entries, one to delete selected entries]

b) make it editable only for the proper users and accomplish the same thing as above. Perhaps not as slick, but less complicated. [maybe…removing an entry is easy, the getActionCommand param would be empty, but when is an entry new and when has it been changed…? add an ‘add new entry’ button that adds a blank entry and selects it(?)]

A new constructor for MyCombo in this case might look like:


public MyCombo( String filename, boolean isAdmin ) {
  this( filename );       //call the other constructor
  setEditable( isAdmin ); //yeah, it gets called twice...take it out of the other one
}

Keep in mind, my code does the minimal amount of work to show that it can work, you’ll need to rewrite the actionPerformed code to suit your needs.

Either way, I hope someone will correct me if I’m wrong, I don’t think there’s a way to ‘reload’ the combo box. You can edit, add and remove entries, but you can’t clear and reload wholesale. (you could iterate through and remove all the entries then reload the file and add them again, but…why?)

As for why, it’s so the list is in alphabetical order.

My main concern is not with the user levels. I’ve already got that pretty much squared away.

How would I go about clearing the box and reloading everything?

setEditable() - It doesn’t have to be editable to be editable

Are you alluding to there being another way to edit other than by using setEditable?

.

Are you alluding to there being another way to edit other than by using setEditable?

No, I’m pointing out that setEditable sets whether or not the combo is editable by the user. It’s always editable by the program. (ie: it does not have be isEditable = true for the program to addItem, removeItem or insertItemAt)

As for why, it’s so the list is in alphabetical order

I understand that you want the list in alpha order. You can do that without resorting to emptying and reloading the combo everytime there’s a change to the contents.

A JComboBox contains a DefaultComboBoxModel, in line with the MVC ideal (MVC being: model, view, controller - a type of program architecture. Data, by MVC, is the model)

The DefaultComboBoxModel contains a Vector, in which it keeps the information that’s displayed in the JComboBox.

I mention this because even though you constructed your JComboBox with an array, the contents are really being stored in a Vector. Vectors are cool. If you haven’t, you really need to read up on them.

What does this mean to you? It means that by using the methods provided to you by the JComboBox, you can maintain the contents of the JComboBox, in memory(fast), rather than dumping the contents, alphabetizing them and writing and reading a file(slow). Once you do that, you simply need to read the file once at startup, and write it once during shutdown.

Below is a small sample of Vector manipulation.
The Vector is loaded with an alphabetized list, then a new entry is inserted at the correct location. (if ‘golf’ was ‘victor’ instead, what would happen?)


import java.util.*;

public class AlphaVector {
  public static void main( String[] args ) {
    Vector vector = new Vector();
    String golf = "golf";
    vector.add( "alpha" );
    vector.add( "foxtrot" );
    vector.add( "mike" );
    vector.add( "tango" );
    for( int i = 0; i < vector.size(); ++i ) {
      if( golf.compareToIgnoreCase( (String)vector.elementAt( i ) ) < 0) {
        vector.insertElementAt( golf, i );
        break;
      }
    }
    for( Iterator i = vector.iterator(); i.hasNext(); ) {
      System.out.println(i.next());
    }
  }
}

note: You don’t have direct access to the underlying Vector in JComboBox, you’ll have to use the JComboBox methods to manipulate it.

Thanks, that helped out a lot :slight_smile:

FileWriter outfile = new FileWriter(dir_path);
                        for(Iterator j = vector.iterator(); j.hasNext(); ) {
                            System.out.println(j.next());
                            outfile.write(j.next() + "\
");
                        }
                        outfile.close();

Now, this part has me hung up. Is that the correct way to write a vector to a file, or does it need a type cast to a string?

[edit]:

outfile.write( (String)vector.elementAt(j.next()) + "\
");

DDM_edit_button.java [126:1] elementAt(int) in java.util.Vector cannot be applied to (java.lang.Object)
                            outfile.write( (String)vector.elementAt(j.next()) + "\
");
                                                         ^

[edit]: hrm. outfile.write( (String)j.next() + "
");
doesn’t seem to work, either.

outfile.write( i.next() + "
" ); works. I found this interesting.

the version of write you’re using looks like this:

public void Writer.write( String string ) throws IOException

so having just outfile.write( i.next() ) would give a compile error complaining about trying to use an Object when a String is required ( Iterator.next() returns an Object ). But, because of +"
", the toString() method of the Object is called and "
" is appended and the resulting String is used to invoke write.

anyway

outfile.write( (String)j.next() + "
"); doesn’t seem to work, either.

should be working just fine, as above, the cast isn’t needed, but it’s almost never a bad idea.

however, if your code still looks something like:

FileWriter outfile = new FileWriter(dir_path);
for(Iterator j = vector.iterator(); j.hasNext(); ) {
System.out.println(j.next());
outfile.write(j.next() + "
");
}
outfile.close();

you’ve written yourself a problem.

The next() method of the Iterator will advance to the next element in the Vector everytime it’s called, so, if you have an odd number of elements, the above code will fail with a NoSuchElementException.

I didn’t even think that the two calls would do that. Thanks for pointing that out.

Everything’s working great now :slight_smile:

Thank you for all your help on this lengthy issue, rushiku :slight_smile: