Reputation: 323
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();
}
Upvotes: 1
Views: 1344
Reputation: 347204
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
Upvotes: 2