I'm writing an app, and in many situations need to have direct access to mainFrame. It's ok if i'll do this(?):
public class Main {
private static JFrame mainFrame();
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
mainFrame = new JFrame(); //....
});
}
//...
public static JFrame getMainFrame() {
return mainFrame;
}
}
I just think that is more easy to access mainFrame direct then to pass it like a reference.
Thanks!
I don't think you need the Singleton pattern if you only have one Main class and you will only have one JFrame in your application. A static variable is good enough on this case. Now, why do you need to get access to the mainFrame?
Do you need to create child frames from that mainFrame?
Do you need to display a message box and you want its parent to be the mainFrame?
Do you have logic in that class?
If you have instance methods in your mainFrame, for example, and you need to access these methods from anywhere in your application, you could make these methods private, create public static methods, and make those static methods get the mainFrame instance and invoke the private methods. Maybe you should remove the logic from other places in your application and add it to the mainFrame class.
It all depends on what you do with this mainFrame object. What you have in place to get into it is not bad, in my opinion.
You might want to consider implementing the Singleton pattern. Extend JFrame to make your AppFrame class, and make that class a Singleton. This is usually frowned upon, but is a solution to what you are looking to do. Most GUI applications have a MVC architecture, and direct access to a View (i.e. the JFrame in your case) is restricted to the Controller classes. You may want to read up on the MVC pattern if you are implementing a GUI based application.
Information on Singleton pattern here.
Information on MVC
Related
I have some initialization code that needs to be run when my Java Swing application starts, without any events being triggered.
My initialization code is in the myInits() function. myInits() does all sorts of thing: reads config from a file, sets the background and some labels, spawns network threads, initializes variables.
From googling and my own knowledge i have figured out different ways to achieve this(please correct me if any of the assumptions stated below are wrong):
Run myInits() when the Window_Opened event is triggered.
This makes sure the GUI is painted and myInits() can access any component and change it. Unfortunately I can't use this method because my application starts hidden and Window_Opened doesn't get triggered.
Put myInits() inside the JFrame constructor:
public class MyFrame extends javax.swing.JFrame {
private MyFrame(){
initComponents(); // <= Auto generated by NetBeans GUI Builder
myInits();
}
}
I suppose there's nothing wrong with this methoed because initComponents() itself does all kinds of GUI manipulation. I used this method and it worked just fine.
But today I changed MyFrame into a Singleton and i got a java.lang.ExceptionInInitializerError. Because myInits() calls MyFrame.getInstance() and by putting it in the constructor I'm technically calling getInstance() inside another getInstance(). I tried making getInstance() synchronized but it didn't work.
Make myInits() public and call it from main() :
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ChatFrame().myInits();
}
});
}
I personally don't like this method because i don't want myInits() to be public. Also because I like number 4 better.
invokeLater myInits() in the constructor.
private myFrame(){
initComponents();
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
myInits();
}
});
}
This is what i myself came up with. Because the instantiation itself is being done in an invokeLater() method(see number 3), I figured I could be sure that myInits() will run after new myFrame(); has finished and i can safely call MyFrame.getInstance().
To sum it up:
1) Are all of these methods correct?
2) Is any of these (or other possible methods i may have not mentioned) considered the best practice?
3) Which one is the best practice for a Singleton JFrame?
4) Why when i synchronized my getInstance() method i still got the java.lang.ExceptionInInitializerError?
In my opinion, if your initialization logic in not ui specific, it should be in main. Extract a separate class out of myinit, and call it in main.
You may also make it singleton using enum, and use it, so that it gets initialized upon first use/ application load.
Say I have the following code:
public class MainDialog extends javax.swing.JFrame
{
static class SubDialog extends javax.swing.JDialog
{
}
}
If I open 'MainDialog.java' in design mode, I can only edit the GUI of the MainDialog class. Is there anyway to edit the SubDialog class in design mode?
Thanks
To even be "close" to been acceptable, the inner dialog would need to be public and static as Netbeans needs a way to create an instance of the dialog.
Most developers will create separate, single based class, based forms which are then configurable in some way (via setters and getters), passing references of what they need backwards and forwards between them.
Personally, I tend to hand code most my UIs and only rely on the form editor when time a is pressure or the layout is especially complex
I have a JFrame application with some variables and a number of SWING widgets. In it I create an instance of another class and pass the JFrame to the child in the constructor. From the child, I can reference the variables, but not the widgets. Why?
// My JFrame
public class Prot2Prom extends JFrame {
// My Child
public Prot2Prom() {
super( "Protocol To PROM" );
Child child = new Child(this);
In the Child class my constructor does
Prot2Prom frame = null;
public Child(Prot2Prom gui) {
frame = gui;
}
The following works:
frame.<parent variable>=x;
The following does not:
frame.textArea.append("Hello");
The textArea cannot be resolved. There were all added with "new". Why can't I see them?
Some notes and recommendations:
This has nothing to do with "widgets" or Swing and all to do with visibility of variables. I'm guessing that textArea is not a public field of the Prot2Prom class.
If variables are public outside classes can "see" them, access them, modify them.
A possible solution is to in fact make the variables that you want other classes to see, public.
In general you really don't want to do this.
Instead much better is to give a class public methods that allow other classes to call and by doing so alter the original class's behavior. In other words, your Swing GUI classes should adhere to good OOPs principles just as any Java class should.
Later you'll want to read up on the MVC or Model, View, Control design pattern as a way of separating out behaviors of your code into separate logical entities, which can make your code much more flexible and powerful.
Edit 1
Regarding your comment:
The "widgets" are all created by WindowsBuilder Pro. I am trying to use the textArea to create my Eclipse Console for a stand alone (jar) application. How can I print to it from a class instantiated by the Frame?
You'll want to give the class that holds the textArea variable a public method:
public void appendTextAreaText(String text) {
textArea.append(text);
}
Then your other classes can append text to the JTextArea. Why is this important? One reason is that if the class that holds textArea will at some times not want to allow other classes the ability to append to this widget, it can have the logic to control this in the method. Thus it gives much more control over the widget to the class that holds it.
e.g.,
public void appendTextAreaText(String text) {
if (allowTextAreaAppend) { // a class boolean field
textArea.append(text);
}
}
As an aside, I also recommend that you put the code generation tool to the side and instead create your Swing GUI's by hand for a bit until you get a firm grasp of Swing and Java fundamentals. This will make your future use of the Swing code generation tool much better and productive.
The textArea cannot be resolved
This message indicates that there is no member class variable called textArea in Prot2Prom. This is possibly a typo. Perhaps the variable is called textarea or defined only locally in the constructor scope.
To work your class would look something like this
public class Prot2Prom extends JFrame {
JTextArea textArea = new JTextArea();
...
A better approach to updating text in a parent component is to create a method to Prot2Prom like so:
public void addText(String text) {
textArea.append(text);
}
This provides more control over how text is added to the JTextArea.
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.
When dedicating a class to a particular Swing component, is it better to extend that particular component, or construct it internally and provide a reference?
public class Foo extends JComponent{
}
OR
public class Foo{
public JComponent getComponent(){
}
}
EDIT
This is what I mean by dedicating
public class Foo{
private static Foo INSTANCE;
public static Foo getInstance(){
if(INSTANCE == null){
INSTANCE = new Foo();
}
}
public void createAndShowComponent(){
//do stuff
}
}
Inside createAndShowComponent(), I create a JComponent with all its components and their respective listeners without exposing the internals of the component I just created.
+1 for Composition over extension. It makes the API much cleaner since you only expose what methods are important for your new component
I agree with jzd it all depends.
Technically speaking, if you are dealing with GUI in my opinion it is best to build components when you need them, by extending for example JComponent. This way you can simply reuse them.
Personally I would never use the 2nd option in my class. I would only have a class return another component only if there is a very good reason for doing so, e.g. to enable user to modify a button look in your complex calendar component.
For a very simple reason each component class should know what it has this component for, and it should control the view accordingly to what is happening. Thus you would have appropriate methods.
I would say extending it would be better. Being able to use all its properties and using it like it is that object makes it a lot simpler to use. Just my personal Opinion. Both ways are good.
If you are dedicating the entire class to it. Might as well make it that by inheritence.
If your object IS a component, than extend it. If not, then use composition.
It really depends on what you are doing. If you want to include your new class on a JPanel for example, you will need to extend the component. If your code can add the component to the correct place on the GUI, then you don't have to extend it.
I would say none of them. Swing components are very (very) rich and can be customized for visualisation (L&F) and behaviour (events) in any manner. Another point is to create a group of different components and lay them out in a JPanel.