Java noob here. My Swing class that extends JDialog does not dispose when the user presses the Windows Close button - java.exe stays in memory. I've stripped the code right down to this shell, I still get this behaviour.
I took a look at other samples, such as at Basic Java Swing, how to exit and dispose of your application/JFrame
When I commented out the two System.exit(0) lines in that sample code, the class in that sample still disposed correctly. What am I missing to make my class dispose?
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog{
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
//System.exit(0);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
You're creating a JFrame and never disposing it here:
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL); // *********
pack();
}
So since the JFrame is alive and a GUI has been rendered, the Swing event thread keeps on running.
If you instead make the JFrame behave so that the program exits on JFrame close, and then explicitly dispose of the JFrame, your program now exits:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
JFrame win = (JFrame) frame.getOwner();
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
win.dispose();
// System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
But this is very kludgy code, to say the least -- what if the owning window isn't a JFrame? What if it's null?
Another solution is to use no JFrame at all, so that when the JDialog is disposed, there's no persisting window left over to make the event thread persist:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super((JFrame)null, title);
pack();
}
}
Related
I've got a problem with my program what I can't solve. I'm trying for hours and tried to google, etc... I've seen many programs, which is working, but I don't know why my solution does not. My goal (for now) is simple, I want to write to the cmd-line in case of a mouse click or a key press. The first one works, but the second is not. Can anyone tell my why?
import java.awt.EventQueue;
import javax.swing.JFrame;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class test {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test window = new test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public test() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.getContentPane().addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("Mouse has clicked!");
}
});
frame.getContentPane().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println("A key has pressed.");
}
});
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Well, finally I had enough time trying to find the solution and now I'm discovered it. I do not know why, but it was not possible to add a keyListener to the JFrame. I could only add for a JButton or a JTextField, etc... This is strange for me, a little bit :c
UPDATE #3: After madProgrammer's suggestions, maybe the timed solution is the best. But no answer has been given to this strange behaviour.
I understand the fact that components are not shown immediately and need to be set.
The problem here is the onShow method, which executes correctly if called from onCreate, but doesn't work if called from the callback method "componentShown".
UPDATE #2: Added a componentListener on fragmentContentPane, to see when actually this component is shown and VALID
fragmentContentPane.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
if (e.getComponent().isValid()) System.out.println("SHOWN AND VALID!");
}
});
UPDATE:
The show method now gets called in EDT.
public void show() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
System.out.println("Showing..");
frame.setVisible(true);
}
});
}
By now, the problem still exists.
Original Post:
I have this code:
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TEST {
private JFrame frame;
private JScrollPane contentPane;
private JPanel contentViewport;
private JScrollPane fragmentContentPane;
private JPanel fragmentContentViewport;
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
}
});
}
public void onCreate(){
System.out.println("On create!");
frame=new JFrame();
contentPane=new JScrollPane();
contentViewport=new JPanel();
contentPane.setViewportView(contentViewport);
frame.setContentPane(contentPane);
frame.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
onShow();
}
});
}
public void onShow(){
System.out.println("On show!");
fragmentContentViewport=new JPanel();
fragmentContentPane=new JScrollPane(fragmentContentViewport);
fragmentContentPane.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if (e.getChangeFlags()==HierarchyEvent.SHOWING_CHANGED && fragmentContentPane.isShowing()) {
System.out.println("Component is completely shown");
}
}
});
contentViewport.add(fragmentContentPane);
}
public void show(){
frame.setVisible(true);
}
public static final void main(String[] args) throws InvocationTargetException, InterruptedException{
TEST t=new TEST();
t.show();
}
}
The task is simple. I want to get known when the fragmentContentPane has been correctly added and is completely shown.
With this code this never happens, why?
Everything works if the onShow method is called in the ThreadEvent together with onCreate, for example:
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
onShow();
}
});
}
any help is appreciated
When opening a file in a JTree, the tree's preferred size changes but his propertyChangeListener doesn't detect it (but if you change it calling setPreferredSize is able to detect it). Is it my code that is wrong or is javax.swing bugged? If this isn't the way of doing this how should I do it. I tested the code with maximumSize as well.
Here is my code, you shouldn't need any external resources:
import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class MyJFrame extends JFrame
{
public MyJFrame()
{
add(new JTree()
{
{
addPropertyChangeListener("preferredSize",
new PropertyChangeListener()
{
public void propertyChange(PropertyChangeEvent evt)
{
System.out.println("preferred size changed");
}
});
new Thread()
{
public void run()
{
while(true)
{
System.out.println("preferred size = "+getPreferredSize());
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
}.start();
}
});
pack();
setVisible(true);
}
public static void main(String[] args)
{
new MyJFrame();
}
}
I have an undecorated JFrame with my own 'header' at the top. It works fine except for telling if the window is out of focus.
I've tried things like
if(!frame.hasFocus()
//Do stuff here
But this obviously won't work when I have other components in the window, such as a JTextField. I haven't found a way to do this so any help is appreciated.
Here is a sample code by which you can implement it:
import java.awt.event.FocusListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class SwingTest {
public static void main(String args[])
{
swing();
}
public static void swing()
{
JFrame g= new JFrame("First");
g.setVisible(true);
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g.setSize(300, 300);
g.setLayout(null);
JLabel l=new JLabel("Times Windows Lost Focus : 0");
l.setBounds(20,10, 200, 60);
g.add(l);
g.addWindowFocusListener( new WindowFocusListener() {
int c=0;
#Override
public void windowLostFocus(WindowEvent e) {
c++;
}
#Override
public void windowGainedFocus(WindowEvent e) {
l.setText("Times Windows Lost Focus :"+c);
//System.out.println(c);
// TODO Auto-generated method stub
}
});;
}
}
I have a class Dmi,Swing components frame and a label.
I have Swing timer. In timer implementation I have two statements for setting text in the label, with a time interval, but I can only see the last setText operation.
import javax.swing.*;
import java.util.Timer.*;
import java.awt.event.*;
class Dmi implements ActionListener
{
Timer tim;
JFrame frame;
JLabel lbl;
Dmi()
{
frame=new JFrame("abc");
lbl=new JLabel("count");
frame.add(lbl);
frame.setVisible(true);
frame.pack();
tim=new Timer(1000,this);
tim.start();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent ae)
{
Thread th1=new Thread();
lbl.setText("abc");
try
{
th1.sleep(300);
}
catch (Exception e)
{
System.out.println(e);
}
lbl.setText("ddd:");
}
public static void main(String[] args)
{
new Dmi();
}
}
Start by taking a closer look at Concurrency in Swing and How to use Swing Timers
A Swing Timer will generate ActionEvents WITHIN the Event Dispatching Thread, which makes them really good for updating the UI from within.
However, your code...
public void actionPerformed(ActionEvent ae)
{
Thread th1=new Thread();
lbl.setText("abc");
try
{
th1.sleep(300);
}
catch (Exception e)
{
System.out.println(e);
}
lbl.setText("ddd:");
}
is blocking the Event Dispatching Thread (through the use of Thread#sleep), which will prevent the EDT from process new repaint events or any other user based events, making your program look as if it's hung.
You're either going to have to devise a solution which allows you to determine the amount of time the timer has been running and change the state based on that or possibly use a SwingWorker instead
For example...
import java.awt.EventQueue;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Dmi {
JFrame frame;
JLabel lbl;
Dmi() {
frame = new JFrame("abc");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lbl = new JLabel("count");
frame.add(lbl);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Worker worker = new Worker();
worker.execute();
}
public class Worker extends SwingWorker<String, String> {
#Override
protected String doInBackground() throws Exception {
while (!isCancelled()) {
Thread.sleep(1000);
publish("abc");
Thread.sleep(300);
publish("def");
}
return null;
}
#Override
protected void process(List<String> chunks) {
lbl.setText(chunks.get(chunks.size() - 1));
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Dmi dmi = new Dmi();
}
});
}
}