I am a beginner and not so familar with Java yet, so the solution to this might be simple.
I have one MainClass that includes the main method. This MainClass creates a JFrame which can have various JPanels inside. I have one class called CommandInput which creates a JPanel containing a JTextArea. Now I want that when the user closes the JFrame of the MainClass that it asks if he wants to save the changes. As the JPanels inside the JFrame vary I do not really want to include this in the MainClass. I know that it is possible for every "SubClass" like the CommandInput to add a windowListener to the JFrame of the MainClass but that does not really seems efficient to me:
public class CommandInput {
public CommandInput(JFrame mainFrame) {
mainFrame.addWindowListener(new java.awt.event.WindowAdapter() {
#Override //Overwrites the normal behavior of this method
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
System.out.println("Closing Event triggered and detected by CommandInput object");
}
});
}
}
Should I maybe rather have one WindowAdapter in the MainClass and add this code to its windowClosing method? And if so how would I do that?
I now solved it in a way that each SubClass adds an anonymous inner class of an interface containing a method that returns if the JFrame can be closed to a list. Only if all of the anonymous inner classes in the list return true the JFrame closes:
public interface ClosingListener {
public boolean allowClosing();
}
public MainClass {
private ArrayList<ClosingListener> closingListeners = new ArrayList<ClosingListener>();
public MainClass() {
JFrame frame = new JFrame();
frame.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
boolean canClose = true;
for (ClosingListener closingListener : closingListeners) {
if (!closingListener.allowClosing()) {
canClose = false;
break;
}
}
if (canClose) {
System.exit(0);
}
}
});
}
public void addClosingListener(ClosingListener closingListener) {
closingListeners.add(closingListener);
}
}
May be you need this
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
int choice = JOptionPane.showConfirmDialog(null, "Save changes?");
if(choice==0) System.exit(0);
}
});
Related
I need some help with a simple java application which makes use of two jframe to get some input parameters. Here's a sketch of my code:
//second jframe, called when the button OK of the first frame is clicked
public class NewParamJFrame extends JFrame{
...
}
//first jframe
public class StartingJFrame extends JFrame{
private static NewParamJFrame newPFrame = null;
private JTextField gnFilePath;
private JButton btnOK;
public StartingJFrame(){
//..
initComponents();
}
private void initComponents(){
btnOK.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
EventQueue.invokeAndWait(new Runnable(){
public void run() {
try {
newPFrame = new NewParamJFrame();
newPFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
catch(InvocationTargetException e2) {}
catch(InterruptedException e1){}
dispose();
}
}
public String getText(){
return gnFilePath.getText();
}
}
public class Main {
private static StartingJFrame begin = null;
public static void main(String[] args) {
try{
EventQueue.invokeAndWait(new Runnable(){
public void run() {
try {
begin = new StartingJFrame();
begin.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
catch(InvocationTargetException e) {}
catch(InterruptedException e1){}
String s= begin.getText();
//...use s ...
}
}
The call to getText() causes a NullPointerException. I want the main class to wait until the frames are closed but I don't know how to do. I'm using swing for the first time.
I want the main class to wait until the frames are closed but I don't
know how to do. I'm using swing for the first time.
If I understand your problem correctly, you need StartingJFrame to stay waiting until NewParamJFrame is closed and then continue its execution. If this is the case then it won't happen because JFrame doesn't support modality. But JDialog does, so you can have just one JFrame and do the parameters request in a JDialog whose parent is this JFrame.
For a better explanation about modality, take a read to How to Use Modality in Dialogs.
Also take a look to this topic: The Use of Multiple JFrames, Good/Bad Practice?
In any case you'll probably face a new problem: what should the JFrame do if the user closes/cancels the dialog withouth input any parameter? How could this JFrame know what just happened in that dialog? One approach is described in this answer. You'll see the example is about a login dialog but the problem is similar to this one: How could a dialog notify to its parent frame on how the process went?
The easiest way to wait for close without modifying the code flow is to use a modal JDialog. So you have to change your StartingJFrame class to make it a subclass of JDialog instead of JFrame, and add the following to the begin of its constructor:
super((Window)null);
setModal(true);
Then the setVisible(true); invocation on the StartingJFrame instance will wait until the dialog has been closed and hence the invokeAndWait invocation will wait too.
The call to getText() causes a NullPointerException.
Because, gnFilePath of JTextField is null.
private JTextField gnFilePath;
public String getText(){
return gnFilePath.getText();// NullPointerException is throw here.
}
To avoid NPE, you need to initialize JTextField and JButton like below.
private JTextField gnFilePath=new JTextField();
private JButton btnOK=new JButton()
Try putting this:
import java.awt.event.*;
import javax.swing.*;
public class MyWindow extends JFrame{
MyWindow(){
setSize(300, 200);
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton b = new JButton("Close");
b.setBounds((300-80)/2, (200-30)/2, 80, 30);
//
final MyWindow frame = this;
b.addActionListener(
new ActionListener(){
#Override
public void actionPerformed(ActionEvent ev){
synchronized(frame){
frame.notify();
}
frame.setVisible(false);
frame.dispose();
}
}
);
//
getContentPane().add(b);
setVisible(true);
synchronized(this){
try{
this.wait();
}
catch(InterruptedException ex){ }
}
}
public static void main(String args[]) {
new MyWindow();
System.out.println("You are here");
}
}
The code above is checked.
Using a JDialog is probably the simplest solution, but in some cases it's desirable to have a JFrame, for example to show the window in the taskbar. Using a synchronization mechanism as suggested by Octavio is a way to achieve this, here is an alternative using a CountDownLatch blocking the main thread until the frame is closed:
public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setSize(300, 200);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
latch.countDown();
}
});
});
latch.await();
System.out.println("Main thread released");
}
You can use a loop (preferably do-while loop) to put a frame on hold until the other frame closes or hides. Make sure to break the loop or increment the variable used for the loop by specific amount when the other frame is disposed or hidden. This way you can keep your StartingJFrame class to remain as a subclass of JFrame.
do {
if (changeLog.isVisible()) {
} else {
changeLog.dispose();
break;
}
} while (hold < 1);
or
do {
if (changeLog.isActive()) {
} else {
break;
}
} while (hold < 1);
The first one would require the previous frame to be hidden (JFrame.HIDE_ON_EXIT or Window.setVisible(false)) before the codes can be run. The last one would require the previous frame to be "disposed" (JFrame.DISPOSE_ON_EXIT or (subclass of JFrame).dispose(). Add any of those codes on StartingJFrame, though, since you created a NewParamJFrame in that class and have the corresponding field(s) set to private.
I am trying to make a program, that automaticly extracts a link from a .json file. I'm new to programming, and I'm trying to organize the code, so other people will be able to understand it more easily.
I have a constructor called Gui, where it adds a close button, and a file explorer with awt. To organize the project, I want to make another class to extract the link, but I can't figure out, how I can refer to the TextField with the file path, in the Gui class's constructor.
I need to get the text from fe in another class.
I have searched the web for hours, but I can't find anything that works for me.
public class Gui extends Frame {
public Gui() {
Frame gui = new Frame(Strings.name);
// add "close" button
Button cls = new Button(Strings.close);
cls.setBounds(30, 30, 100, 30);
gui.add(cls);
cls.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
// file explorer
TextField fe = new TextField(Strings.file);
fe.setBounds(50,100, 200,30);
fe.setLocation(75, 75);
gui.add(fe);
fe.addMouseListener(new MouseListener() {
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {
FileDialog fd = new FileDialog(gui, Strings.cfile, FileDialog.LOAD);
fd.setVisible(true);
fe.setText(fd.getDirectory());
}
});
// make application work
gui.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
gui.setSize(1200, 900);
gui.setLayout(null);
gui.setVisible(true);
}
}
Could try with the following updates
public class Gui extends Frame {
//create an inner class
class MyProcess
{
MyProcess(String s)
{
System.out.println("do something with s="+s);
}
}
public static void main(String args[])
{
new Gui();
}
...
#Override
public void mouseClicked(MouseEvent e) {
FileDialog fd = new FileDialog(gui, "file", FileDialog.LOAD);
fd.setVisible(true);
fe.setText(fd.getDirectory());
//use the inner class as needed
new MyProcess(fe.getText());
}
Possible output on console
do something with s=D:\some_path\
Kindly note that is not mandatory an inner class, could be also an external one. That depends only of your design. Maybe also in the future for graphic interfaces you could do some researches on : JavaFx,Swing maybe Eclipse Graphics Library. Awt library is the most ancient one.
you should put your references to your classes e.g. text outside of your constructor for example,
public class Gui extends Frame {
// your reference
private TextField text;
Gui() {
// now instantiate your textField
text = new TextField();
}
// getter method that returns your textField
public TextField getTextField() {
return text;
}
}
then you can get your text from your gui.
Gui gui = new Gui();
TextField field =gui.getTextField();
I recommend that learn the basics of java programming and then define bigger project for your self.
I have two classes, and from the first jFrame1 (CotizacionGUI) I instantiate and make visible the other one (jFrame2), and I want to pass the instance of this jFrame1 (CotizacionGUI), to the other, in the constructor, to dispose it in an action triggered by the button at any moment...
public class CotizacionGUI extends javax.swing.JFrame{
public CotizacionGUI() {
initComponents();
}
private void buttonCallFrame2ActionPerformed(java.awt.event.ActionEvent evt) {
BuscarCotizacionGUI bC = new BuscarCotizacionGUI(thisjFrameinstance);
bC.setVisible();
}
}
And this is the Frame2 (BuscarCotizacionGUI), here is where I want to dispose the previous jFrame, triggered by the action performed event:
public class BuscarCotizacionGUI extends javax.swing.JFrame {
public BuscarCotizacionGUI(final JFrame otherFrame) {
initComponents();
this.setLocationRelativeTo(null);
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
otherFrame.dispose();
}
});
}
}
Can you help me guys please, I don't want to do it using other class, i want to pass the reference in the jFrame1, Thanks!
The instance of first JFrame is always available to you in the same class as this
public class CotizacionGUI extends javax.swing.JFrame{
public CotizacionGUI() {
initComponents();
}
private void buttonCallFrame2ActionPerformed(java.awt.event.ActionEvent evt) {
BuscarCotizacionGUI bC = new BuscarCotizacionGUI(this);
bC.setVisible();
}
}
Hope this is what you are looking for.
Good luck.
I have 2 classes.
One extends canvas and inside creates a jframe and add the canvas to that jframe and add another keyadapter class to receive key events. I also have main function to test the code. When running from main, the form is displayed and recieves key events too.
Now i create another class that extends jframe and implements keylistener to receive events in this form.
Once the functionality done in the second class i want to close the second form and show the first form. When showing it from the key event functions in the second class the first class key listener is not working.
Please just have a glimpse at my code and tell me how to correct my prob. Thanks for your time and valuable suggestion.
Class 1
public class Test extends Canvas {
private JFrame container;
public Test() {
container = new JFrame("Space Invaders");
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(screenSize.width, screenSize.height));
panel.setLayout(null);
setBounds(0, 0, screenSize.width, screenSize.height);
panel.add(this);
container.pack();
container.setResizable(false);
container.setVisible(true);
try {
addKeyListener(new KeyInputHandler(this));
} catch (Exception e) {
e.printStackTrace();
}
requestFocus();
}
private class KeyInputHandler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
//Some Action
}
public void keyReleased(KeyEvent e) {
//Some Action
}
public void keyTyped(KeyEvent e) {
//Some Action
}
}
public static void main(String args[]){
//Running this canvas here works perfectly with all added keylisteners
}
}
Class 2
public class Sample extends JFrame implements KeyListener {
public Sample() {
init();
this.setSize(100, 100);
this.setVisible(true);
Sample.this.dispose();
// Created a window here and doing some operation and finally redirecting
// to the previous test window. Even now the test window works perfectly
// with all keylisteners
new Test();
}
public static void main(String[] args) {
new Sample();
}
private void init() {
addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
removeKeyListener(this);
Sample.this.dispose();
// But when calling the previous Test window here, the window
// gets displayed but the keylistener is not added to the
// window. No keys are detected in test window.
new Test();
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Simple dont use KeyListener/KeyAdapter that is for AWT components and has known focus issues when used with Swing.
The issues can be got around by making sure your component is focusable via setFocusable(true) and than call requestFocusInWindow() after component has been added/is visible.
Rather use KeyBindings for Swing.
For example say now we wanted to listen for D pressed and released:
public static void addKeyBindings(JComponent jc) {
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "D pressed");
jc.getActionMap().put("D pressed", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D pressed");
}
});
jc.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "D released");
jc.getActionMap().put("D released", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("D released");
}
});
}
We would call this method like:
JPanel ourPanel=new JPanel();
...
addKeyBindings(ourPanel);//adds keybindings to the panel
Other suggestions on code
Always create and manipulate Swing components on Event Dispatch Thread, via SwingUtilities.invokeLater(Runnable r) block
Dont extend JFrame class unnecessarily
Dont implement interfaces on a class unless the class will be used for that purpose, or other classes need access to the interfaces methods.
As mentioned by #AndrewThompson, dont use multiple JFrames, either swap the rest for JDialog, or use CardLayout. See here for an example.
I want my GUI to make some checks when a JOptionPane appears.
Because I can't find any other way, I though I can do those each time the application window loses focus(its just checking a string). For that reason I added the following code on my JFrame:
appFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowLostFocus(WindowEvent e) {
System.out.println("Focus Lost");
}
#Override
public void windowClosing(WindowEvent e) {
//some other stuff here that work
}
});
The window closing listener works fine. Although when the JFrame isn't focused nothing happens. Shouldn't "Focus Lost" be printed each time I switch from JFrame to some other window? Also, will this method be triggered when a JOptionPane is shown?
The key to me is that you want a change in the GUI triggered by a change of a String variable. The best way I see to solve this is to make the String variable a bound property by using PropertyChangeListenerSupport. This way you can have the GUI attach a PropertyChangeListener to the class that holds the String variable and then be notified when it changes allowing you to update the GUI appropriately.
If you go this route, consider giving the observed class a SwingPropertyChangeSupport field so that the listeners will be notified on the Swing event thread and hopefully avoid any Swing concurrency issues.
Here's a brief example:
import java.awt.Dimension;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class ShowPropertyChangeSupport {
#SuppressWarnings("serial")
private static void createAndShowGui() {
final MainGUI mainGui = new MainGUI("Title");
final ObservedClass observedClass = new ObservedClass();
observedClass.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals(ObservedClass.BOUND_PROPERTY)) {
mainGui.setTitle(pcEvt.getNewValue().toString());
}
}
});
mainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainGui.pack();
mainGui.setLocationRelativeTo(null);
mainGui.setVisible(true);
int timerDelay = 6000; // every 6 seconds
new Timer(timerDelay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
String result = JOptionPane.showInputDialog(mainGui,
"Please enter a String", "Set GUI title", JOptionPane.PLAIN_MESSAGE);
if (result != null) {
observedClass.setBoundProperty(result);
}
}
}){{setInitialDelay(1000);}}.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
// ** note that I don't like extending JFrame,
// but will do this for sake of example simplicity
class MainGUI extends JFrame {
public MainGUI(String title) {
super(title);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
}
class ObservedClass {
public static final String BOUND_PROPERTY = "bound property";
private String boundProperty = "";
private SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
this);
public SwingPropertyChangeSupport getSpcSupport() {
return spcSupport;
}
public void setSpcSupport(SwingPropertyChangeSupport spcSupport) {
this.spcSupport = spcSupport;
}
public String getBoundProperty() {
return boundProperty;
}
public void setBoundProperty(String boundProperty) {
String oldValue = this.boundProperty;
String newValue = boundProperty;
this.boundProperty = newValue;
spcSupport.firePropertyChange(BOUND_PROPERTY, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
spcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
spcSupport.removePropertyChangeListener(listener);
}
}
The key to all this in my mind is to use the listener so that the class with the bound property -- the String being listened to -- has no knowledge of the GUI, the listener, and the GUI, likewise has no knowledge of the class with the bound property. They are fully decoupled.
I'm not going to go into why you are doing what you are doing, but it is not working as you expect for the following reason:
WindowAdapter is a convenience class so you can create one listener and register it for multiple types of events. You have only registered it for one set of events, you need to also register it for focus events via: Window.addWindowFocusListener()
WindowAdapter adapter = new WindowAdapter() {
#Override
public void windowLostFocus(WindowEvent e) {
System.out.println("Focus Lost");
}
#Override
public void windowClosing(WindowEvent e) {
//some other stuff here that work
}
};
appFrame.addWindowListener(adapter);
appFrame.addWindowFocusListener(adapter);
1) JOptionPane / modal JDialog have got modality issue, but modality could be advantage if all containers have got own owner, for real workaround you need to know (I'll talking about how can I do test that)
numbers of Window[], and if isDisplayable(), then you can use follows
you can get SwingUtilities#getAccessibleIndexInXxx can returns AccessibleState
KeyboardFocusManager (very interesting methods for multi-touch) returns getXxxFocusXxx methods
Focus, FocusSubsystem is pretty asynchronous,
2) Please, with due respect, I don't know why you needed that, for why reasons I need to know about that, there is about business rules, you always need to know ...., and if is done on EDT
Focus, FocusSubsystem is pretty asynchronous,