Somehow I cannot access & close a JFrame with.dispose(), and it gives me a nullPointerException. Neither do I want to do a System.exit(0). How do I access the JFrame directly, is there a workaround to close the JFrame?
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
frame = new ScannerUI();
frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
... (further down, and I cannot access the JFrame already, gives me a nullpointerexception)
btnBack.setBounds(400, 270, 80, 40);
panel.add(btnBack);
btnBack.setText ("BACK");
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//ScannerUI.DISPOSE_ON_CLOSE();
//frame.dispose();
//this.dispose();
//frame.setVisible(false);
//System.out.println ("dsakjf;dsalkhfsa;lklf");
//System.exit(0);
//JFrame test = ScannerUI.frame;
//test.dispose();
// p = false;
System.out.println ("asdfasfas");
System.exit(frame.dispose());
}
});
You could use the SwingUtilities method, getWindowAncestor, to help you get the window that holds the button and then call dispose on it:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
AbstractButton button = (AbstractButton) e.getSource();
Window window = SwingUtilities.getWindowAncestor(button);
window.dispose();
}
});
Another option is to get the enclosing object of the current class (if it is the JFrame). You can get this from within your anonymous inner class by using the class name, a period, followed by this, or for you: ScannerUI.this:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ScannerUI.this.dispose();
}
});
You can also check out Closing an Application and use the ExitAction. This is a more generic solution that will simulate a user clicking the "X" on the window. In this case any WindowsListeners you have added to the frame will be invoked first before the window is closed.
May not be applicable in this case, but just something to think about.
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 creating an application in Java and I would like that when you minimize to an icon, the application will have to "hide" in the system tray.
The code I use is this: (the significant part of the code)
myFrame = new JFrame();
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
#Override
public void windowDeiconified(WindowEvent e) {
System.out.println("Deiconified");
}
});
This is a "PutTray" function:
private void PutTray()
{
try
{
tray.add(trayIcon); // Initialized elsewhere
myFrame.setVisible(false);
} catch (AWTException e) {
System.err.println(e);
}
}
To restore (via option in the pop-up menu when you press the icon minimized):
MenuItem show = new MenuItem("Show");
show.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFrame.setVisible(true);
myFrame.setState(JFrame.NORMAL);
tray.remove(trayIcon);
}
});
The code works perfectly on Windows 8, but it does not work on Linux (Kali Linux and even Ubuntu).
Why Windows yes and Linux no?
EDIT:
On Linux, after you press the command to show the application, it appears for a very small moment, and then minimizes again. Basically is triggered the event "windowDeiconified" and immediately after the event "windowIconified" without taking the time to do something else and then the application is shown in the system tray.
As Dan Getz suggests, I also thought the order of setVisible and setState should be inverted since the javadoc for setState says:
If the frame is not visible on the
* screen, the events may or may not be
* generated.
but this didn't help.
The one thing that did help though was replacing setVisible(false) with dispose(). They are similar in that you can use setVisible(true) to reopen a disposed window. You can read more about it here: JDialog setVisible(false) vs dispose()
I'll try to find an explanation and come back with it :)
SSCCE to simulate OP problem:
public class Test {
private JFrame myFrame;
public Test() {
myFrame = new JFrame();
myFrame.setVisible(true);
myFrame.setSize(300, 300);
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
});
}
private void PutTray() {
myFrame.setVisible(false); //replace with dispose(); and it's ok
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
myFrame.setVisible(true);
}
});
t.setRepeats(false);
t.start();
}
public static void main(String[] args) {
new Test();
}
}
I think you are getting it wrong!
Maybe you are confused about deiconified and visibility
windowIconified()
will be called when we click minimize button
and
windowDeiconified()
is called when we restore it from taskbar and not system tray!
In order to restore from system tray you need to use this
trayIcon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
window.setVisible(true);
}
});
Basically i don't think the difference between dispose() & setVisible() will bother you in this specific problem
Still, my recommendation is to use setVisible() here
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.
If a JFrame window is minimized, is there any way to bring it back to focus?
I am trying to get it to click a certain point, then restore it.
while (isRunning) {
start = System.currentTimeMillis();
frame.setState(Frame.ICONIFIED);
robot.mouseMove(clickX, clickY);
robot.mousePress(InputEvent.BUTTON1_MASK);
frame.setState(Frame.NORMAL);
Thread.sleep(clickMs - (System.currentTimeMillis() - start));
}
If you want to bring it back from being iconified, you can just set its state to normal:
JFrame frame = new JFrame(...);
// Show the frame
frame.setVisible(true);
// Sleep for 5 seconds, then minimize
Thread.sleep(5000);
frame.setState(java.awt.Frame.ICONIFIED);
// Sleep for 5 seconds, then restore
Thread.sleep(5000);
frame.setState(java.awt.Frame.NORMAL);
Example from here.
There are also WindowEvents that are triggered whenever the state is changed and a WindowListener interface that handles these triggers.In this case, you might use:
public class YourClass implements WindowListener {
...
public void windowDeiconified(WindowEvent e) {
// Do something when the window is restored
}
}
If you are wanting to check another program's state change, there isn't a "pure Java" solution, but just requires getting the window's ID.
You can set the state to normal:
frame.setState(NORMAL);
Full example:
public class FrameTest extends JFrame {
public FrameTest() {
final JFrame miniFrame = new JFrame();
final JButton miniButton = new JButton(
new AbstractAction("Minimize me") {
public void actionPerformed(ActionEvent e) {
miniFrame.setState(ICONIFIED);
}
});
miniFrame.add(miniButton);
miniFrame.pack();
miniFrame.setVisible(true);
add(new JButton(new AbstractAction("Open") {
public void actionPerformed(ActionEvent e) {
miniFrame.setState(NORMAL);
miniFrame.toFront();
miniButton.requestFocusInWindow();
}
}));
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new FrameTest();
}
}
I'm in the process of creating a GUI in Netbeans 6.1 for my senior design project but i've run into an annoying snag. Temporary Windows like my login PopUp and others wont disappear when i tell it. I've been researching how to solve this for about 2 months on an off. I've even mad a separate thread for my Pop Up but it still wont work....the only way it will disappear if i literally dont mess with any of the other GUI components....my sample code should help describe my anger...dont mind the shadow code, it was for testing purposes, which obviously didnt help.
//This method is called once a user presses the "first" login button on the main GUI
public synchronized void loginPopUpThread() {
doHelloWorld = new Thread(){
#Override
public synchronized void run()
{
try
{
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
System.out.println("waitin");
doHelloWorld.wait();
System.out.println("Not Sleepin..");
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(false);
}
catch (InterruptedException e)
{
}
}
};
doHelloWorld.start();
//This is called when the "second" loginB is pressed and the password is correct...
public synchronized void notifyPopUp() {
synchronized(doHelloWorld) {
doHelloWorld.notifyAll();
System.out.println("Notified");
}
}
I've also tried Swing Utilities but maybe i implemented it wrong as it's my first time using them. It essentially does the same thing as the code above except the window freezes when it gets to wait, which the above code doesnt do:
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public synchronized void run() {
try
{
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
System.out.println("waitin");
wait();
System.out.println("Not Sleepin.");
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(false);
}
catch (InterruptedException e)
{
}
}
});
PLEASE HELP ME!!!
Rules of thumb:
Don't manipulate GUI components in arbitrary threads; always arrange to manipulate them in the event thread
Never wait or sleep inside the event thread (so, never inside code sent to invokeLater())
So the answer to how you solve this problem is "some other way"...
Standing back from the problem a bit, what is it you're actually trying to do? If you just want a login dialog to wait for the user to enter user name and password, is there a reason not to just use a modal JDialog (after all, that's what it's there for...).
If you really do want some arbitrary thread to wait for a signal to close the window/manipulate the GUI, then you need to do the waiting in the other thread, and then make that thread call SwingUtilities.invokeLater() with the actual GUI manipulation code.
P.S. There are actually some GUI manipulation methods that it is safe to call from other threads, e.g. calls that are "just setting a label" are often safe. But which calls are safe isn't terribly well-defined, so it's best just to avoid the issue in practice.
The Swing components should only be manipulated by the swing event dispatch thread.
class SwingUtilites has methods to submit tasks to the dispatch thread.
It is difficult to diagnose your problem. I'm not sure what you're trying to do with the wait methods, but I recommend leaving wait/notify alone.
This code has two frames - when you create a second frame, the first is hidden until you close it.
public class SwapFrames {
private JFrame frame;
private JFrame createMainFrame() {
JButton openOtherFrameButton = new JButton(
"Show other frame");
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(openOtherFrameButton);
frame.pack();
openOtherFrameButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
onClickOpenOtherFrame();
}
});
return frame;
}
private void onClickOpenOtherFrame() {
frame.setVisible(false);
JFrame otherFrame = new JFrame();
otherFrame
.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
otherFrame.setContentPane(new JLabel(
"Close this to make other frame reappear."));
otherFrame.pack();
otherFrame.setVisible(true);
otherFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
frame.setVisible(true);
}
});
}
public static void main(String[] args) {
JFrame frame = new SwapFrames().createMainFrame();
frame.setVisible(true);
}
}
Because I don't see any evidence of them in your code, I'm going to suggest you read up on using event listeners rather than trying to "wait" for code to finish.
It isn't entirely clear what you're trying to achieve, but you might be better off with a modal dialog:
public class DialogDemo {
public JFrame createApplicationFrame() {
JButton openDialogButton = new JButton("Open Dialog");
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = frame.getContentPane();
container.setLayout(new FlowLayout());
container.add(openDialogButton);
frame.pack();
openDialogButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
onOpenDialog(frame);
}
});
return frame;
}
private void onOpenDialog(JFrame frame) {
JDialog dialog = createDialog(frame);
dialog.setVisible(true);
}
private JDialog createDialog(JFrame parent) {
JButton closeDialogButton = new JButton("Close");
boolean modal = true;
final JDialog dialog = new JDialog(parent, modal);
dialog
.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
Container container = dialog.getContentPane();
container.add(closeDialogButton);
dialog.pack();
dialog.setLocationRelativeTo(parent);
closeDialogButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
}
});
return dialog;
}
public static void main(String[] args) {
new DialogDemo().createApplicationFrame().setVisible(
true);
}
}
How about doing simply:
//This method is called once a user presses the "first" login button on the main GUI
public void loginPopUpThread() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
}
};
}
//This is called when the "second" loginB is pressed and the password is correct...
public void notifyPopUp() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loginPopUpFrame.setVisible(false);
}
};
}
What you really want to be using is a modal JDialog.
Note, bits of this are left out. It's your homework/project.
public void actionPerformed(ActionEvent e)
{
// User clicked the login button
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
LoginDialog ld = new LoginDialog();
// Will block
ld.setVisible(true);
}
});
}
public class LoginDialog extends JDialog
{
public LoginDialog()
{
super((Frame)null, "Login Dialog", true);
// create buttons/labels/components, add listeners, etc
}
public void actionPerformed(ActionEvent e)
{
// user probably clicked login
// valid their info
if(validUser)
{
// This will release the modality of the JDialog and free up the rest of the app
setVisible(false);
dispose();
}
else
{
// bad user ! scold them angrily, a frowny face will do
}
}
}