How does composite object communicate with parent object? - java

I am from system programming background in C and Java programming is Greek and Latin for me.
So my problem is:- I have 2 JFrame Objects
I have a parent Object A
which has child Objects B.
Object B has buttons on it.
If a button is clicked in B I want to update the UI of parent Object.
How can I can communicate to the parent - to update itself?

Do the updates need to be made 'live' while the values are adjusting and the 2nd GUI is open, or can they be delayed until it is closed?
They can be delayed until it is closed.
Use a modal dialog or JOptionPane instead.
How to Make Dialogs
How to Use Modality in Dialogs
Using a modal dialog, whatever code line comes immediately after setting it visible, is blocked from being processed until it is closed. That is where you examine (the return value of the option pane &) the value of the controls you put in the dialog. Note that the idea here is do not extend dialog. Instead just create an instance of one in the main code, create the controls, add them to it, and show it using the main frame as the parent.
Putting 'everything in one class' is not a good design, nor what I am suggesting in general. It is just that there is little cause here for the main GUI not to have references to controls that affect/update it.

Well normally you have a parent JFrame object into which you put your widgets like buttons, panels etc.
You can simply add an anonymous action listener with the button and then call any function of the parent class from inside it.
public class MyFrame extends JFrame{
private Button button 2 = new Button();
public void init(){
b = new Button("Click me");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
//CALL ANY FUNCTION OF PARENT CLASS FROM HERE.
updateText();
}
});
}
updateText(){
this.button2.setText("new text");
}
}
You can find more info about it on this page http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

I have found one more way to solve this problem.
I guess it can solve a general delegation problem.
Parent Object composes of Child Object.
Parent Object passes this value to Child Object in constructor.
This way the Child can call a method on the Parent Object and notify any change.
In this case Child Frame calls Parent frame and asks the parent to refresh itself.

Related

Java use event handler on multiple buttons dynamically and in a clean way

I want the event handler to be added to one parent that contains many buttons. That event listener then analyzes bubbled events to find a match on child nodes which I can target. With other words, right now I do this:
for(Object button: menuButtons) {
button.setOnAction(handler);
}
Now I have all buttons attached to an event handler, great but not what I want. I just want them to have one handler on the parent and use that to somehow fire the different buttons. Is it possible?
One way is to make your own Button class to apply the listener for you:
public class MyButton extends Button {
public MyButton(MyHandler handler) {
super();
setOnAction(handler);
}
}
Then in your parent code:
MyHandler handler = new MyHandler(...);
MyButton menuButton1 = new MyButton(handler);
MyButton menuButton2 = new MyButton(handler);
...
I'm not sure why you want to do this though, because the handler will receive events from all the buttons. You'll have to distinguish between them.
Edit: Actually, after reading the question again I'm not sure if this is what you're asking for. You want to apply the listener to the parent and have it indirectly be passed to the buttons? I'm not sure if that is possible. It would depend on what type of object the parent is, and even then if the parent was to receive events it wouldn't be able to know what buttons were clicked (unless you do some ugly stuff maybe, like checking the coordinates of the touch with the coordinates of the buttons, but I don't think that's worth it). With this solution you are keeping it to one MyHandler object, but that was the case in your original solution too.

How to access widgets from within listener?

I am building a GUI with SWT by using WindowBuilder for Eclipse. When you drag'n'drop widgets onto your shell in WindowBuilder, your source code gets automatically generated. However, all the widget objects are declared in the createContents function. The following is an excerpt from that function:
Button btnStartServer = new Button(shlTest, SWT.NONE);
btnStartServer.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// how to access serverStateDisplay right here?
// I have access to shlTest (my Shell object), though
}
});
btnStartServer.setText("Start Server");
Canvas serverStateDisplay = new Canvas(shlTest, SWT.NONE);
As you can see, I have a selection listener that get's triggered when I click a button. Now, how can I access the canvas? The obvious solution, simply writing serverStateDisplay.doWhatever() is not working.
I found this SO question which essentially asks the same thing. However, the only solutions were to either declare the referenced widget before the listener or to declare it as a class instance variable.
This is not satisfying for me, since I build my UI with WindowBuilder. Can't WB do this automatically for me? Because when the application grows, it will be quite uncomfortable manually changing each widget declaration.
The same goes for the main loop. With the widgets declared inside the createContents function, they are not accessible once the function terminates.
Indeed, to access a widget you should either declare it a field or try to get the Widget from the selection event.
In your case, I would prefer exposing your canvas as a field.
In Window Builder, to expose a local variable as a field: select the variable, then click on the button "Convert local to field".

How to close a called class using JFrame without closing the class that called it?

I seem to have a fairly unique problem, and I searched for a while for an answer on here without finding one. I have a class that has a simple JFrame with two buttons. Each button calls the Main method of a different class, as such:
checkRuling = new JButton("Check Your Deck's Rulings");
checkRuling.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
ReadHtmlCardDatabase.main(null);
}
});
One calls a class that takes a series of inputs into a text field and creates a formatted html document from the inputs, and the other loads the html document into a JEditorPane. My problem is that when I close one of the JFrames for the subclasses (either the input or html loader one), it exits my program completely, and I want to keep the main class (with the two buttons) open. I've tried using:
close = new JButton("CLOSE");
close.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
System.exit(1);
}
});
On a button in the subclasses, to no avail. When the button is clicked it simply exits everything. I've also tried using:
JFrame.DISPOSE_ON_EXIT
For the subclasses, but this causes the JFrames to go away without the subclasses actually closing, so the first one that saves the html document never actually saves it, and the second subclass that opens that same html document won't work, because it wasn't saved. Any help would be appreciated, because I can't figure out how to do this.
As Fast Snail says in the comments, you shouldn't be calling a main method. Instantiate a class that does each functonality. Set the frame to visible using setVisible(true) when you start using it, then setVisible(false) when you're done. So, in the action listener, just change the visibility.
Then, assuming you don't have anything too wild going on, the frame you just set to invisible should go out of scope and get freed so that memory isn't chewed up. You just instantiate a new copy of the ReadHtmlCardDatabase class each time you need one. Or you could have one static copy that you set visible/invisible as needed.
one of the JFrames
You should use only one JFrame in Your GUI. For other windows You can use for example JDialog or JWindow.
This should help, if not You can always use frame.setVisible(false) instead of dispose on close, but it' s not very neat.
Thanks to someone who posted a comment and then deleted it, I've figured out my own problem. I just had to replace my main call with this:
setDeck = new JButton("Set Deck");
setDeck.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
WriteHtmlCardDatabase w = new WriteHtmlCardDatabase();
w.main(null);
}
});
Thank you!

Bringing specific Jdialog to front when having multiple jdialogs in one application

I have multiple JDialogs in my application stored in a map. These JDialogs are all have
setModel(false);
When these dialogs are out of focus and I want to bring a specific JDialog toFront all JDialogs come toFront. I want the specific Jdialog to come to front and want the other JDialogs to remain in back.
HashMap<String, JDialog> jDialogMap = getJDialogMap();
String key = "jd1";
JDialog specificJDialog= jDialogMap.get(key);
if (specificJDialog== null){
specificJDialog= new JDialog();
specificJDialog.setModel(false);
specificJDialog.setVisible(true);
jDialogMap.put("jd2", specificJDialog);
} else {
specificJDialog.toFront();
return;
}
This code brings all the JDialogs toFront having the specificJDialog on top of the stack.
getJDialogMap();
This Method only returns a HashMap nothing else.
use requiredDialogObject.requestFocusInWindow();
whenever u need focus on the specific dialog
I found a solution to my problem I think it is worth sharing it.
Solution: Creating multiple JDilogs in an application with default constructor i.e. new JDialog() will result in a shared frame as the parent of each JDialog which will cause these kind of problems. So I used the overloaded constructor new JDialog(new JFrame()) to have separate parent for each JDialog and that solved my problem.
Had a similar issue. After opening the JDialog my main application window just requested the focus again, moving the JDialog window to the background, which was annoying. I experimented with modal() and toFront() methods, which both didn't work out for me, since modal() just prevented user interaction completely (outside of that JDialog) and toFront() also has effect on windows outside my application (by using it inside of a timer method, see below).
To keep the window in front of the main application I used a timer method, which was fired every 300 ms and just keeps requesting the focus by using the requestFocus() method.
import javax.swing.Timer;
Timer timer = new Timer(300, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
requestFocus();
}
});
timer.start();

Passing objects from JDialog back to root frame

Let's say we have a JFrame frame that contains two JPanels, buttonPanel and dataPanel, and in this panel a single JButton button. When clicked, button creates and shows a JDialog dialog in its own window (as usual). Using several JTextFields and a submit button, the JDialog dialog creates a new Object dataObject encapsulating these input data. If we wish our dataPanel JPanel in the main application frame to display this dataObject, how should dataObject be appropriately passed to the JPanel residing in a foreign JFrame?
That was a mouthful even to me while writing it, so I'll attempt to clarify:
JFrame frame
JPanel dataPanel - meant to display data from Objects created in the JDialog
JPanel buttonPanel - contains a button to open the JDialog, into which some information will be entered and with said information our Object dataObject is constructed.
The goal here is to pass this dataObject (and it's constituent fields) to the dataPanel to be displayed. What is the most appropriate way to handle this? I considered keeping the Objects in dataPanel static and then calling a static method from the JDialog to add the new object, but it doesn't seem the proper thing to do.
Some guidance?
Much will depend on the structure of your program, including how the dialog is supposed to behave:
If the JDialog is modal and disappears when the submit button has been pushed, then the solution is easy -- extract the data from the dialog-related class after it returns which will be the line of code right after where you display the dialog. The dialog's submit JButton's listener could simply make the dialog no longer visible.
Otherwise if the JDialog is non-modal and disappears when the submit button has been pushed, then you may wish to attach a Listener to its Window, I believe a WindowListener, and then have your calling code extract the information when the listener indicates that the dialog has been closed or is closing.
Otherwise, if the JDialog is non-modal and is not supposed to become invisible when the submit button has been pressed but you need to update the calling program with new data, then I would have the calling class add a PropertyChangeListener onto the dialog-related class so that the dialog-related class can notify any listeners that submit has been pressed. This code would be in the dialog's submit JButton's listener.
I would give a dialog-related class a public DataObject getDataObject() method that the calling code can call once the dialog returns, allowing the class that displays the dialog to extract the pertinent information when needed.
Whatever you do, there is no reason to use static fields and many reasons not to. I strongly urge you to not even consider this.
For example of a modal dialog that returns:
// caveat: code has not been tested by compilation or running.
JButton myButton = new JButton(new AbstractAction("Show Dialog Button") {
public void actionPerformed(ActionEvent evt) {
MyDialogPanel myDialogPanel = new MyDialogPanel();
JDialog myDialog = new JDialog(myJFrame, "My Dialog",
ModalityType.APPLICATION_MODAL);
myDialog.add(myDialogPanel);
myDialog.pack();
myDialog.setLocationRelativeTo(myJFrame);
myDialog.setVisible(true);
// dialog now returns and we can get the data
// assuming that the wrapper object for your data
// is called "DataObject"
DataObject dataObject = myDialogPanel.getDataObject();
// and perhaps use it. Assume setDataObject is a method
// of the main GUI that displays the data object
setDataObject(dataObject);
}
});

Categories

Resources