I have a java swing application which has a processWindowEvent method.
below is the snippet
#Override
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
//exit application with proper error message
}
}
Now when my swing application is launched in windows.
close with the cross in swing UI. ==> proper error message is shown
close the application from taskbar ==>proper error message is shown
but now if the same step is done in mac.
close with the cross in swing UI. ==> proper error message is shown
close the application from taskbar ==>does not come inside above method. So no proper message.
I wanted to know what is the default method which will be called in mac when java swing app is closed from taskbar(the dock)
A world without com.apple.eawt.*
You need to look towards java.awt.Desktop instead.
For example...
Desktop.getDesktop().setQuitHandler(new QuitHandler() {
#Override
public void handleQuitRequestWith(QuitEvent e, QuitResponse response) {
// Do some stuff
//response.cancelQuit();
//response.performQuit();
}
});
Desktop.getDesktop().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
Original Answer
Welcome to the wonderful world of "Apple does everything differently"
Basically what's happening is, when you "Quit" the program, Apple is calling System.exit(0), basically the same thing that would occur if your used CMD+Q
Now, Apple provides an API which provides functionality which you can use to "configure" your App with MacOS and perform some functionality which is unique to Apple, the problem is, it's a complete pain in the ... code to find useful information about and use.
What you're looking for is com.apple.eawt.ApplictionsetQuitStrategy. This defaults to calling System.exit(0), but you can change it to "close all windows" instead.
In this case, it would allow you to trap the WindowEvent and do what ever it is you want to do
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.out.println("Closing");
System.exit(0);
}
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
try {
Class quitStrategies = Class.forName("com.apple.eawt.QuitStrategy");
Object quitStrategy = null;
for (Object o : quitStrategies.getEnumConstants()) {
if ("CLOSE_ALL_WINDOWS".equals(o.toString())) {
quitStrategy = o;
}
}
if (quitStrategy != null) {
Class appClass = Class.forName("com.apple.eawt.Application");
Class params[] = new Class[]{};
Method getApplication = appClass.getMethod("getApplication", params);
Object application = getApplication.invoke(appClass);
Method setQuitStrategy = application.getClass().getMethod("setQuitStrategy", quitStrategies);
setQuitStrategy.invoke(application, quitStrategy);
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
}
}
My general advice is, build a nice "Mac" utilities class which encapsulates the functionality you want to play with and call that.
Also beware, this functionality may disappear suddenly in future releases.
It should be noted that if you intend to have a "one for all" application, you will need to use reflection, as the required API is not available in the standard API, but if you wanted to make a "Apple" only release, you should have a look at this for more information about how you can compile the code on MacOS, because using...
Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
is hell of a lot easier to write and understand
To catch window close event you need to add WindowListener and override method windowClosing. Use this code:
JFrame frame = new JFrame(...);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener( new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
JFrame frame = (JFrame)e.getSource();
....................
}
}
Related
Can anyone guide me on why 'frame.dispose();' doesn't dispose the frame? The other method is called but 'frame.dispose();' is just ignored. This java class is used to check whether a stored answer that is made from another java class (RecoveryQuestion.check()) is the same as the user's input. Public variables such as StoredQuestion and StoredPassword are in the RecoveryQuestion class as well. Furthermore, I'm using Intelli J IDEA GUI form and I don't know how to extract the code, however, the form runs smoothly as intended except with the frame.dispose();
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.IOException;
public class ForgotPassword {
private JPanel panel1;
private JTextField answer;
private JLabel Question;
private JButton Submit;
private JFrame frame = new JFrame("Password Reset");
public ForgotPassword() {
Submit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(RecoveryQuestion.StoredPassword.equals(answer.getText())) {
//frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
frame.dispose();
FirstRun.main(null);
}
else JOptionPane.showMessageDialog(null,"Incorrect Answer");
}
});
}
public void setUI() {
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setContentPane(new ForgotPassword().panel1);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(400,250));
frame.pack();
frame.setResizable(false);
}
public static void main(String[] args) {
try{
RecoveryQuestion.Check();
} catch(IOException e1) {}
new ForgotPassword().setUI();
}
private void createUIComponents() {
// TODO: place custom component creation code here
Question = new JLabel();
Question.setText(RecoveryQuestion.StoredQuestion);
}
}
Every call to new ForgotPassword() does just that -- it creates a completely new and unique ForgotPassword instance. Look at your code above, and count how many times that you call this -- I see two times, suggesting that your problem is that you're displaying a JFrame from one of these instances, and trying to dispose of it in another -- two different JFrames that are unrelated to each other.
Suggestions:
Your code is very convoluted with instances creating instances of them self within their self. Simplify.
Create only one ForgotPassword in your GUI and pass it where needed
Side issue: shouldn't this sort of window be a dialog window (i.e., a JDialog) and not an application window (i.e., a JFrame)?
If your code did work as intended, then calling .dispose() on this JFrame should cause the JVM to exit (the entire program to end) since you're setting its default close operation to EXIT_ON_CLOSE.
Side issue 2: your posted code is not a valid MCVE meaning we cannot easily copy the code, paste it into our IDE and compile and run it without modification, making it more difficult for us to fully understand your code and forcing me to guess at your problem. In the future (and now), please consider posting one of these. Note that we do not want to see your entire program, nor should you post a link to a code repository. Instead keep it small, keep it simple, and make it functioning.
Why can't I call the setModal() method?
I am working on GUI. I have two jframes. The following code is for a button and is supposed to open the other frame. But i get error that says:
cannot find method setModal(boolean)
private void jButton3_actionPerformed(ActionEvent e)
{
HR hr = new HR();
if(f == 1){ // condition
hr.setModal(true); // give me error here ?
hr.setVisible(true);
}else{
jLabel5.setText("You aren't connected...");
}
}
hr.java
import java.awt.Dimension;
import javax.swing.JFrame;
public class HR extends JFrame {
public HR() {
try {
jbInit();
} catch (Exception e) {
e.printStackTrace();
}
}
private void jbInit() throws Exception {
this.getContentPane().setLayout( null );
this.setSize( new Dimension(400, 300) );
}
}
I am working on GUI I have two jframes
An application should only have a single parent JFrame. Other child windows should be a JDialog and you specify the frame as the parent.
A JDialog DOES have the setModal(...) method.
You create a JDialog the same way you create a JFrame.
JFrame class has no setModal(boolean) method..
refer to the doc here
therefore you CAN NOT invoke that method, your HR class must instead have defined that method... but I see in the update that actually the HR class is not defining it...
I've programmed a DLL in C. The first function sends a pointer of the callback function that is called when new data is available.
So I use JNA to wrap this function.
In order to avoid the end of the app, I use an InputStreamReader that wait data from the standard input. And when new data are available the callback is called and data are printed in the console.
But, if I use a JFrame to avoid the end of the program before closing the window, it doesn’t work properly. In fact, if I don’t resize the JFrame window, the callback is called about 30 times and after that nothing (even if new data are available). If I resize the window, the callback if never called (even if new data are available).
Please could you help me?
Thanks
Edit : This is my main method.
package jsigmausblib;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import javax.swing.JFrame;
public class JSigmaUSBLib {
public static void main(String[] args) {
NativeSigmaUSBLibInterface nsuli = (NativeSigmaUSBLibInterface) Native.loadLibrary("SigmaUSBLib1.0", NativeSigmaUSBLibInterface.class);
ReadCallback rc = new ReadCallback() {
#Override
public void callbackFunction(Pointer readData, byte len) {
System.out.println("ok"+readData.getByte(0));
}
};
SigmaUSBLibConfigStruct.ByValue config = new SigmaUSBLibConfigStruct.ByValue();
nsuli.SigmaUSBLibInit(rc , config);
JFrame frame = new JFrame("Debug");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(80, 60);
frame.setVisible(true);
}
}
Following my previous two posts here and another one here, the following code
opens the regular file browser instead of the expanded one:
public class GuiHandler extends javax.swing.JFrame {
// data members
private DataParser xmlParser = new DataParser();
private File newFile;
JFileChooser jfc = new JFileChooser();
// more code
public void launchFileChooser() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(Exception e) {
e.printStackTrace();
}
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
jfc.setAcceptAllFileFilterUsed(false);
if (jfc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
newFile = jfc.getSelectedFile();
}
});
}
// more code
private void XMLfilesBrowserActionPerformed(java.awt.event.ActionEvent evt) {
launchFileChooser();
xmlParser.getNodeListFromFile(newFile);
// here the code has the below problems
Problems:
The code opens a regular file browser when I hit a button to open XML file; it still allows me to pick a file.
It throws an exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: File cannot be null
at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:198)
Why does it open the regular browser if jfc is a data member, and when it's a local
variable, the expanded one opens?
Concerning the regular versus expanded file chooser, make sure to call UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); before calling new JFileChooser();. Actually, unless you allow users to change the look and feel (L&F) during application execution, set the L&F close to the beginning of application execution, like in the main method, before creating any Swing components. From my experience, not doing so can cause some odd UI behavior.
When you have JFileChooser as a local variable in launchFileChooser, UIManager.setLookAndFeel is called before new JFileChooser. When JFileChooser is a class member variable (a.k.a. data member), UIManager.setLookAndFeel is called after new JFileChooser; in the latter case, the JFileChooser is created when an instance of GuiHandler is instantiated.
Concerning the IllegalArgumentException use SwingUtilities.invokeAndWait in launchFileChooser instead of SwingUtilities.invokeLater. Better yet, if you're sure launchFileChooser will always occur on the event dispatch thread, there's no need to call either SwingUtilities.invokeAndWait or SwingUtilities.invokeLater.
You also may want to use a file filter:
jfc.setFileFilter(new FileNameExtensionFilter("XML files (*.xml)", "xml"));
The following is an SSCE that demonstrates the concepts discussed above:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;
public class GuiHandler extends JFrame {
public static void main(String[] args) throws Exception {
// call UIManager.setLookAndFeel early in application execution
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new GuiHandler();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private final JFileChooser jfc;
public GuiHandler() {
this.jfc = new JFileChooser();
this.jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
this.jfc.setFileFilter(new FileNameExtensionFilter("XML files (*.xml)", "xml"));
final JButton button = new JButton("Open XML file");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
xmlFilesBrowserActionPerformed();
}
});
add(button);
pack();
}
protected void xmlFilesBrowserActionPerformed() {
final File xmlFile = getXmlFile();
if (xmlFile != null) {
System.out.println(xmlFile); // process XML file
}
}
private File getXmlFile() {
// At this point we should be on the event dispatch thread,
// so there is no need to call SwingUtilities.invokeLater
// or SwingUtilities.invokeAndWait.
if (this.jfc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
return this.jfc.getSelectedFile();
}
return null;
}
}
I'm not exactly sure what you mean by 'expanded one' but I assume you are referring to the file filter. In absence of any file filter, I'm guessing it's defaulting to showing all files. Try adding the following code before opening the dialog.
jfc.setFileFilter(new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
return f.isDirectory() || f.getName().toLowerCase().endsWith(".xml");
}
public String getDescription(){
return "XML File";
}
})
Is it possible to implement a wrapper application for other (Java) applications using Java?
The purpose is to enforce usage policies for documents independent of the application used to work with a specific document.
E.G. I have an encrypted file that needs to be decrypted and opened in some kind of editor. So the wrapper application would decrypt the file and start the editor within itself to enforce an read-only policy by denying the write-access to the application, for example. Therefore the Runtime.getRuntime().exec(<command>) method doesn't fit well :)
There are also some ways to intercept method invocations within the same application but none that would wrap a whole other application.
I've also read about altering the JVM itself to intercept the file access. That sounds pretty good. But I need to dynamically change the policy depending on a user. That might not work as far as I know by now.
I guess there might not be any way to do this using Java code, but I'd appreciate any kind of hints and help.
I've also read about altering the JVM itself to intercept the file access. That sounds pretty good. But i need to dynamically change the policy depending on a user.
Set a custom SecurityManager that overrides checkWrite(String) to throw an exception.
Here is a simple example that prevents child frames from exiting the VM (checkExit(int)).
import java.awt.GridLayout;
import java.awt.event.*;
import java.security.Permission;
import javax.swing.*;
/** NoExit demonstrates how to prevent 'child' applications from
* ending the VM with a call to System.exit(0). */
public class NoExit extends JFrame implements ActionListener {
JButton frameLaunch = new JButton("Frame");
JButton exitLaunch = new JButton("Exit");
/** Stores a reference to the original security manager. */
ExitManager sm;
public NoExit() {
super("Launcher Application");
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
sm = new ExitManager( System.getSecurityManager() );
System.setSecurityManager(sm);
setLayout(new GridLayout(0,1));
frameLaunch.addActionListener(this);
exitLaunch.addActionListener(this);
add( frameLaunch );
add( exitLaunch );
pack();
setSize( getPreferredSize() );
setLocationByPlatform(true);
}
public void actionPerformed(ActionEvent ae) {
if ( ae.getSource()==frameLaunch ) {
TargetFrame tf = new TargetFrame();
} else {
// change back to the standard SM that allows exit.
System.setSecurityManager(
sm.getOriginalSecurityManager() );
// exit the VM when *we* want
System.exit(0);
}
}
public static void main(String[] args) {
NoExit ne = new NoExit();
ne.setVisible(true);
}
}
/** Our custom ExitManager does not allow the VM to exit, but does
* allow itself to be replaced by the original security manager. */
class ExitManager extends SecurityManager {
SecurityManager original;
ExitManager(SecurityManager original) {
this.original = original;
}
/** Deny permission to exit the VM. */
public void checkExit(int status) {
throw( new SecurityException() );
}
/** Allow this security manager to be replaced,
if fact, allow pretty much everything. */
public void checkPermission(Permission perm) {
}
public SecurityManager getOriginalSecurityManager() {
return original;
}
}
/** This example frame attempts to System.exit(0) on closing, we must
* prevent it from doing so. */
class TargetFrame extends JFrame {
TargetFrame() {
super("Close Me!");
add(new JLabel("Hi!"));
addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.out.println("Bye!");
System.exit(0);
}
});
pack();
setSize( getPreferredSize() );
setLocationByPlatform(true);
setVisible(true);
}
}
The Eclipse RPC may be a good option to look at. It provides editor views which can easily be changed to enable / disable save, and other functionality at run time. Since Eclipse is written in Java, most Java code you already have will play nice with the framework.