1

Two classes in my program are causing me trouble. The first opens up a JFrame. The second updates data on a .properties file. Within the JFrame there is a panel with JTextAreas and a button "Save Changes." When that button is pressed I call a method from the second class but to do that I have to
firstClass x = new firstClass(); So when the button is pressed, the file is updated but a new JFrame opens up. I'm pretty sure creating the instance x is what's causing this, but I don't know any other way to accomplish this without doing that.

Class 1:

public class firstClass{    
    public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable(){
                @Override
                public void run(){
                    new firstClass();
                }
            });
        }

JFrame go = new JFrame("firstClass");
JPanel panel = new JPanel();
JTextArea textArea = new JTextArea();
JButton savechanges = new JButton("Save");

public firstClass() {
    panel.add(textArea);
    panel.add(savechanges);

    savechanges.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent arg0){
            secondClass f = new secondClass();
            try {
                f.UpdateData();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

    go.add(panel);
    go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    go.setSize(750, 750);
    go.setVisible(true);
}

Class 2:

public class secondClass {
    public static void main(String[] args) {
        //creates properties file
    }

        public void UpdateData() throws IOException{
        firstClass x = new firstClass();  // <-------------------------------
        FileInputStream in = new FileInputStream("config.properties");
        Properties props = new Properties();
        props.load(in);
        in.close();

        FileOutputStream out = new FileOutputStream("config.properties");
        props.setProperty("prop1", x.textArea.getText().toString());
        props.store(out, null);
        out.close();

    }
Oscar F
  • 323
  • 2
  • 9
  • 21

1 Answers1

2

You're crossing purposes, who's actually in control here and who is responsible for what??

Separate the areas of responsibility, for example, your SecondClass is only (really) responsible for collecting data from the user, where as your FirstClass is actually the one who knows what that data should be used, the SecondClass shouldn't care...

Think of it like this, the SecondClass is the waiter, it takes the order and gives that information to the FirstClass, who is the chef, who knows how to fulfil the order and prepare the meal...

Instead of using separate frames (see The Use of Multiple JFrames, Good/Bad Practice? for some reasons why you shouldn't), consider using a modal JDialog of some kine.

The dialog should collect the information from the user, when it is closed, based on how it is closed, use the caller to process and handle the result...

SecondClass secondClass = new SecondClass();
int reason = secondClass.showDialog();
if (reason == SAVE_RESULTS) {
    //... Get the data from the secondClass and save it...
}

See How to Make Dialogs for more details

Updated

Okay, so what you seem to want is some kind of "configuration" manager which is capable of storing/retrieving values.

The configuration manager will know how to read and write the properties and will not care about anything else, it has a clearly defined boundary. You will then need to ask the configuration manager to read or write values as needed...

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TestConfig {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestConfig();
            }
        });
    }

    JFrame go = new JFrame("firstClass");
    JPanel panel = new JPanel();
    JTextArea textArea = new JTextArea();
    JButton savechanges = new JButton("Save");

    public TestConfig() {
        panel.add(textArea);
        panel.add(savechanges);

        savechanges.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                try {
                    ConfigurationManager.INSTANCE.put("prop1", textArea.getText());
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(panel, "Failed to write properties", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

        go.add(panel);
        go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        go.setSize(750, 750);
        go.setVisible(true);

    }

    public enum ConfigurationManager {

        INSTANCE;

        protected Properties readProperties() throws IOException {
            Properties p = new Properties();
            try (FileInputStream fis = new FileInputStream("config.properties")) {
                p.load(fis);
            }
            return p;
        }

        public String get(String name) throws IOException {
            return readProperties().getProperty(name);
        }

        public void put(String key, String vaue) throws IOException {            
            Properties p =  readProperties();
            p.put(key, vaue);
            writeProperties(p);            
        }

        protected void writeProperties(Properties p) throws IOException {
            try (FileOutputStream fos = new FileOutputStream("config.properties")) {
                p.store(fos, "Config");
            }
        }            
    }
}

This example is very heavy handed...each time you read a value, it loads the contents from disk and each time you set the value, it stores to disk.

You could cache the values in memory, reading them once when it's first loaded and writing at some time the future, but I hope you get the idea none-the-less

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I see your point, I'm just not sure how I'm crossing purposes. Class 1 has only one JFrame with a few panels (using cardLayout so only one panel is shown at a time) so I don't think I'm using separate frames. Class 1 is the chef, as you put it, and Class 2 is the waiter, just collecting information. The reason I want the info in the file is so that when the user closes the application and re opens it, the data previously entered is still there. I just don't want another instance of the frame to open up when I save the data. – Oscar F Sep 15 '14 at 03:53
  • So give the information back to the chef...You don't even need to create a second instance of `firstClass` in `secondClass`, simply pass it the details it needs to save.... – MadProgrammer Sep 15 '14 at 03:57
  • The chef would be getting the information from the config.properties file that was updated in `secondClass`. The way I passed the details that the user entered in the textArea was using this: `props.setProperty("prop1", x.textArea.getText().toString());` but this wouldn't work without a second instance of `firstClass`? – Oscar F Sep 15 '14 at 04:07
  • What you "seem" to need, is some kind of configuration manager to manager the storage and retrieval of the settings... – MadProgrammer Sep 15 '14 at 04:11
  • Looks like I was just over-thinking again... all I did was move the `UpdateData` method over to `firstClass` and it works fine. I think that's what you were trying to tell me by crossing purposes.. – Oscar F Sep 15 '14 at 04:31
  • Yes and no ... ;) - Personally, I'd still separate the responsibility for the management of the configuration from the GUI, but that's just me... – MadProgrammer Sep 15 '14 at 04:33
  • I just want everything working and considering I've never worked with enumeration, I think I'll leave it as is for now and take a look into the configuration manager later on just to try and make the code a bit cleaner. Thanks! – Oscar F Sep 15 '14 at 04:46