How can I reference a variable in one JFrame from another JFrame? - java

I have a JFrame with buttons and when I click one of the buttons an integer decreases by 1. I am trying to show the integer in another JFrame but when I reference it I get an error saying non static variable cannot be referenced in a static context. How can I make this a non static variable?
Here is the code from when a button is clicked.
private void DietPepsiBTNActionPerformed(java.awt.event.ActionEvent evt) {
MessageLBL.setText("Enjoy your Diet Pepsi!");
credit -= 1.00;
stCredit = Double.toString(credit);
CreditAMT.setText("$" + stCredit);
Refresh();
dietPepsi -= 1;

Provide some kind accessor in the master frame (to allow other components to read the value) (something like getValue() for example).
When ever the value is changed, fire some kind of event. You could cheat and use a PropertyChange event which would require you not to add any additional code, or you could fire something like a change event that notifies the other frame that the value has changed.
The second frame would then use the getValue method to read the value.
This would require the second frame to have a reference to the master (so it can get the value).
Better yet, just create a model, allow the model to fire events and share the model.
Have a look at Observer Pattern for more details

Brendon's answer is close. Ideally what you do what he suggests, create a separate object and pass it in to each frame. The frames then share the objects. Since the frames themselves will have references to the object, you don't need any kind of global reference.
YourModel model = new YourModel();
Frame1 frame1 = new Frame1(yourModel);
Frame2 frame2 = new Frame2(yourModel);
Additionally, you implement the PropertyChangeListener idiom to where each frame subscribes to the property changes in YourModel.
That way, when Frame1 makes changes to YourModel, Frame2 will be notified of them and can keep itself up to date automatically.
Then the game becomes a matter wiring together objects and their listeners. After that, it's almost magic how it all works together.
Ref: http://docs.oracle.com/javase/tutorial/uiswing/events/propertychangelistener.html

Make a third object and pass a reference to both jframes. This shared object can store any properties that you need

Related

How to update a panel which shows details of an object

I have a panel, let's call it detailsPanel, which holds a Person reference and displays its field values in the following manner:
Name: person.getName ();
Surname: person.getSurname ();
Emain: person.getEmail ();
.... .......
.... .......
And so on. I will use JLabels (correctly aligned using a GridBagLayout) to show each (fieldName, fieldValue). I have a lot of fields to display.
The problem is that the panel which shows the details must be always visible, i.e it will not be shown in a modal JDialog, so that i could create the panel by simply reading my Person object fields at the panel creation.
The panel must always be visible, and its Person reference will change when the user selects a different row in a Person list. This means i will call a method to update its state, something like:
detailsPanel.setPerson (aPerson);
Now, i'm wondering how i should update all the fields. Should i keep a reference to all the JLabels which show the values, and use setText(value) on each of them when i update the panel, or would it be better to override getText() method for every label, returning the correct field value, so that in the update method i would only repaint the panel, and the text would automatically change when the getter method is used on a different Person object?
Any suggestion is appreciated!
Since this is UI stuff which is usually called almost never (relative to how often things are called in other computation) you don't need to worry about efficiency at all. Just do what you think is the most elegant solution. There are three options That quickly come to my mind. They are ordered from quick and static to elegant and reusable:
Quick and dirty: create your constructor and make everything look nice. Then move everything from the constructor to a separate init() method and every time the entities change, you just call removeAll(); and then init() again.
As you suggested, keep a reference to all labels and use the setPerson() method to update all panels. Then call this method in the constructor (this is arguably the most common solution).
As you suggested, build your own extension of JLabel. This new class should either have an update() method which is to be called when things change, or have it set its own listeners to ensure that it gets notified of any relevant change.
If you are planning to create a single panel which is supposed to display all kinds of objects, you could have those object implement an interface called Displayable which gives you generic access to all its values and maybe even listeners to each value. An alternative to the Displayable interface is to use reflection and use annotations to allow the panel to get its values for display.
Please note that the most elegant solution is - contrary to what some people may tell you - not always the best for any situation. How much maintenance do you expect there to be in the future? How big is the application? Will you ever hand off the code to someone else? All these and more need to be considered to decide how "nice" you want your solution to be.

How to get data out of GUI Form (IntelliJ)

I am relatively new to Java and I am using IntelliJ's GUI Form wizard to create a form that uses a main() method to create the Form.
I can get the Form to create, and have added a listener to the submit button, but I am not sure about how to get the form values back out into the rest of the application.
Because the form uses main, I can only pass in Strings, and it doesn't return anything so I can't get a reference to the frame so I can't create a method to pass in a reference to the object to populate.
Because the form uses main, I can only pass in Strings, and it doesn't return anything so I can't get a reference to the frame so I can't create a method to pass in a reference to the object to populate
You should go back to the basics of OOP. The GUI designers really hide this from you, and it takes much refactoring to get them functionally clean.
You can create any instance of your class. And run that via main()
For example.
public class Gui {
private JFrame frame;
private JTextField textField;
public Gui(String title) {
frame = new JFrame(title);
}
public void run() {
// display Frame, add panels, etc
}
public String getDataFromGui() {
return textField.getText(); // for example
}
// other methods
public static void main(String[] args) {
Gui g = new Gui("Hello World!");
g.run();
}
}
Added a project to showcase this. [Link here]
In order to get data back to the first frame we would need to use the same memory reference.
Simplifying the explanation:
Imagine you have a bucket.
The first frame tells the second frame in what bucket to place the data.
The Second Frame doesn't know the data yet but knows in which bucket to place it.
The User adds the data and clicks Ok button.
The Second Frame takes the data and places them in the bucket.
Back in the first frame we take the data from the bucket.
In the project, the Bucket is the instance of DataObject, which is passed to the SecondForm and upon clicking its button we add the value to that bucket.
Finally, a WindowFocusListener to update the field when we get back to the first frame.
Code is self-explanatory.
With functional programming, the code can be improved further. Checkout this branch .

Can I call componentShown() method from a class that extends JFrame instead of JPanel ? If yes, how?

I want to show one JLabel and one JComboBox when one particular RadioButton is selected in previous frame, otherwise it should be hidden. Even when I implement ComponentListener in that class his abstract methods(componentShown(), componentHidden()) are never called.
I think that your problem can be handled pretty easily, without even getting into these event handlers. Just pass a variable from your initial frame, when the RadioButton is selected, to the new frame (maybe a boolean variable with true value). Then, in your new fame, simply show the components, based on the value of that variable.
I hope you can handle the passing of variables, by handling the constructor parameters of your new frame.
Hope this helps ! Any clarifications required, please comment.

Reset JComponent to default value

For example, if component is a checkbox it must set to false, or it is a textfield it must be clear the text. I am trying to write a method for reset all components in a JPanel. It must work like reset function in HTML forms.
How to reset a JComponent to the default value?
As a good developer, you probably have a nice separation between view and model. When the model gets updated, those changes are then reflected in the view.
If you have such structure, you could simply reset your model to a default state, and that reset-ed state then become visible in the UI (which means the UI is reset to its default state)
One possible workaround would be to create a custom reset function. Reinitialize the panel ( your form).
For e.g.
void reset(){
//recreate the form panel.
formPanel = new FormPanel();
}
Create a custom class FormPanel to store the form fields and their listeners.
Re initializing the panel components would result in an overhead of reassigning the listeners as #Robin suggested.
There is no reset function in Swing. The best way to do this is to create a method with the values you want to reset and set everything here e.g. :
public void resetWindow(){
checkBox.setSelected(false);
textField.setText("");
}
The advantage of using this way is that you can just reuse this method whenever you want to reset and also when the class loads.
The other way you could do it is by creating another instance of your Panel and throwing away the original. That way everything would be in the start state.
Write a method which sets the initial values of all elements on start. Then you can reuse this initialization method to "reset" the values.
there is no reset sort of method for swing component, your code should handle it.

Using Inner classes correctly (how to share class in user event)

I am trying to program a java application that consists of several windows using JFrame.
Each JFrame contains a JTextField and buton to go to the next JFrame.
I need to retrieve all the information entered by the user at the end.
I created an event click on the buton to save to a public class all the data that the user introduce in the JTextField. I named that public class myData, which has a static attributes.
The problem is that I can not access this class from the button listener function.
I get an error: cannot refer to an non final variable inside an inner class defined in a different method.
My goal is to be able to share the class myData between different methods of a different class.
E.g. I have a class named myClass1 and myClass2, so I want to share the myData attribute between myClass1 methods and myClass2 methods.
Please anyone can someone help me? or propose another way to do this!
Thanks in advance !
All of the calls about MVC etc. are valid, but this isn't that hard.
What you want to do is in your Main, you can create your Data (Model) class, the class that holds all of your information.
So, you can do something like this:
public class F1 ... {
private final Data myData;
public F1(Data theData) {
myData = theData;
}
....
}
public class Main {
Data myData;
public static void main(String args[]) {
Main m = new Main();
m.setMyData(new Data());
F1 f = new F1(m.getMyData());
...
}
}
Then, later, when F1 calls F2, simply do the same thing -- create F2 with the Data passed in earlier by the constructor. That way, as each Frame runs its course, they're all working on the same instance of Data. When all is done, the single instance of Data is left within the Main class for you to do with what you will.
There are better ways to reorganize your entire program, but this should give you ideas on how to get over the hump you're having right now.
Addenda:
There are several things you can do.
When your get the ActionEvent, it contains a source. That source is the component that generated the event (most likely a Button in this case). If you know where the button is located in the hierarchy of things, you get to your Frame directly. In the pastebin example, you have Frame -> Panel -> Button. So, if you have the Button, you cat get to the Frame.
public void actionPerformed(ActionEvent e) {
JButton sourceButton = (JButton)e.getSource();
F1 f1 = (F1)sourceButton.getParent().getParent();
Data myData = f1.getMyData();
data.setField(...);
}
Again, this is not the recommended ways of doing things. The tutorials have decent examples of using MVC and property change listeners and the whole kit. But this should get you to where you want to go.
Sorry, but your design needs alot of work. I'm going to recommend you read up on MVC. it may seem like alot to chew on right now but it will help you immensely in the long run. On a side note, dont nest your data class definition(s), and remember to always distinguish between classes and objects.
Your overall design of swapping JFrame's seems a bit iffy to me. Why not instead use either dialogs such as a JDialog or JOptionPane or even better a CardLayout to swap views. Also I urge you not to use static fields for any of this as this can cause significant problems in the future and makes your code less compliant with good object oriented principles. With regards to information sharing, about all I can say is that it's all about one class having the proper reference to the other class. For more specific advice you'll likely need to show us more information and code.
Edit
Also, you know of course that you can get a reference to the JButton that stimulated the ActionListener by calling getSource() on the ActionEvent object passed into the actionPerformed method. This may allow you to get a reference to the class that holds the JButton if necessary.

Categories