0

I am trying to write application which will create new window when pressing button, show current window count and close window and thread on closing the window.

So basically, functionality is like this (and some of them are working):

  1. Show window on launching application (OK)
  2. Create new window on pressing button (OK)
  3. Display current window count on pressing button (OK on creating, NOK on closing windows)
  4. Destroy window when pressed "X" (OK)
  5. Destroy main thread when original window is closed (NOK)

Here is my code:

package projectpackage;

import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
import java.awt.*;
import java.awt.event.*;

class MyMouseEvent extends MouseAdapter 
{ 
    public void mousePressed(MouseEvent me)
    { 
      MyWindowThread.incrementMyWindowThreadCount();

      MyWindowThread obj1 = new MyWindowThread();

      Thread thr1 = new Thread(obj1); 

      thr1.start();

    }
}

class MyWindowThread extends JFrame implements Runnable
{

  private int height;
  private int width;

  private static int MyWindowThreadCount = 1;

  public static int getMyWindowThreadCount()
  {
    return MyWindowThreadCount;
  }

  public static void incrementMyWindowThreadCount()
  {
    MyWindowThreadCount++;
  }

  public static void decrementMyWindowThreadCount()
  {
    MyWindowThreadCount--;
  }

  public MyWindowThread()
  {
    super("Frame "+getMyWindowThreadCount());

    this.setHeight(300);

    this.setWidth(400);

    this.setBounds(100,100,getWidth(),getHeight());

    this.addWindowListener(new WindowAdapter()
                            {
                             @Override
                             public void windowClosing(WindowEvent e)
                             {
                                MyWindowThread.decrementMyWindowThreadCount();
                                //Thread.currentThread().interrupt(); 
                                return; 
                             }
                            }
                            );

    JPanel panel1 = new JPanel();

    JButton button1 = new JButton("New window");

    JButton button2 = new JButton("Count running windows");

    this.getContentPane().add(panel1);

    panel1.add(button1);

    panel1.add(button2);

    button1.addMouseListener(new MyMouseEvent());

    button2.addMouseListener(new MouseAdapter()
                             {
                               public void mousePressed(MouseEvent me)
                               {
                                 javax.swing.JOptionPane.showMessageDialog(null,"Window count = " + MyWindowThread.getMyWindowThreadCount());
                               }
                             }
                            );

    this.setVisible(true); // show frame
  }

  public int getHeight()
  {
   return this.height;
  }

  public void setHeight(int h)
  {
   this.height = h;
  }

  public int getWidth()
  {
   return this.width;
  }

  public void setWidth(int w)
  {
   this.width = w;
  }

  public void run()
  {

  }

}

public class MyApp 
{

  public static void main(String[] args)
  {
    // Creating objects START

    MyWindowThread obj1 = new MyWindowThread(); 

    Thread thr1 = new Thread(obj1); 

    thr1.start();
  }

}

manifest.mf:

Manifest-Version: 1.0
Main-Class: projectpackage.MyApp

I hope you know how to compile and run Java application in console. In case you don't, here it is:

(navigate in CLI to directory with "projectpackage" directory inside. *.java file must be inside "projectpackage" directory)


    javac projectpackage\*.java
    jar cfm MyApp.jar manifest.mf projectpackage\*
    java -jar MyApp.jar

Can anyone enlighten me what am I doing wrong or just what I need to do to make the code work? Or am I just having fundamental misconception?

t3rmin41
  • 668
  • 2
  • 8
  • 18

2 Answers2

2
JFrame frame = new JFrame();

This is your problem, you extend the JFrame-class but try to use a new object. You should replace this line by super(); or super("Frame " + getMyThreadCount()); if you want so.

Edit: Another issue to mention: you named your class MyThread, this is a quite irritating class-name for a window ;)

Edit 2: Few other things:

  • public void run() has no content, so why does MyThread implement Runnable?
  • You create some threads, but if I got that right, you do not start any of them.
kelunik
  • 6,750
  • 2
  • 41
  • 70
  • "public void run() has no content, so why does MyThread implement Runnable?" - I am just trying to get familiar with threads in Java, my code worked (well, half-worked) so I left it as it is. "You create some threads, but if I got that right, you do not start any of them." - do you mean that I need add in class MyMouseEvent method mousePressed line "thr1.start();" ? "You named your class MyThread, this is a quite irritating class-name for a window ;)" - will rename it to "MyWindowThread" – t3rmin41 May 15 '13 at 05:31
  • I added thr1.start(); in main() and mousePressed() methods, changed "JFrame frame = new JFrame();" to "super("Frame " + getMyThreadCount());" and "frame.addWindowListener();" to "this.addWindowListener();" -> now when I add windows, window adding is OK, though they all come with title "Frame 1", though pressing on button "Count windows" shows OK. But when I close one window, that window closes OK, but I cannot close other windows! I mean, if I have 3 windows, the first window is closed OK (any creation order), and other 2 windows do not respond on pressing "X" – t3rmin41 May 15 '13 at 05:56
  • I think it's because `Thread.currentThread().interrupt()` interrupts the Java-main-thread. – kelunik May 15 '13 at 12:17
  • and what should I do? I mean, how should I change code, which part? – t3rmin41 May 15 '13 at 13:38
  • What happens if you comment out this line? – kelunik May 15 '13 at 13:39
  • launched the same code (haven't comment your proposed line just yet) on other PC (WinXP 32bit) and now sometimes I can do what I want (close windows and get correct window count by pressing button "Count windows"), sometimes Java frames become unresponsive. Another unexpected result is that when I create new JFrame by pressing button, the second frame (first is original frame created on launch) gets title "Frame 1" when it should get title "Frame 2". Then tried to comment the line "...interrupt();" : now titles and behaviour is as expected (at least I haven't got unexpected results yet) – t3rmin41 May 15 '13 at 18:35
  • Recode, looks like application behavior now is OK. Can you propose what should I change so that when I close the last window (relevantly or irrelevantly to creation order), the main thread will terminate, too? Because now when I close all windows, I see in console that application is still running (need to Ctrl+C to terminate it). – t3rmin41 May 15 '13 at 18:42
  • The easiest way would probably be to check on `decrementMyWindowThreadCount()` if `MyWindowThreadCount==0`, if so, call `System.exit(0);` – kelunik May 15 '13 at 19:13
1

If you simply want your application to exit when the JFrame is closed, then you are going about this all wrong. Get rid of all the Thread objects and Runnables. Swing applications run in the event dispatch thread (EDT). You should only use background threads if you need to do something like disk or network I/O.

Create/show the JFrame in the EDT. If you set the default close operation on the JFrame to DISPOSE_ON_CLOSE, then when all of the windows have been closed, the main thread will terminate normally.

public class MyApp {

    public static void main( String[] args ) {
        EventQueue.invokeLater( new Runnable() {
            public void run() {
                MyWindow w = new MyWindow();
                w.setVisible( true );
            }
        } );
    }

    private static class MyWindow extends JFrame {

        // Simplified reference counting
        private static AtomicInteger frameCount = new AtomicInteger( 0 );
        public MyWindow() {
            super("Frame " + frameCount.incrementAndGet() );   
            this.setSize( 400, 300 );
            this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
            JButton button = new JButton("New Window");
            button.addActionListener( new ActionListener() {

                @Override
                public void actionPerformed( ActionEvent e ) {
                    MyWindow w = new MyWindow();
                    w.setVisible( true );
                }
            } );

            this.getContentPane().add( button );
            // ignore reference count button for now
        }

    }
}
wolfcastle
  • 5,850
  • 3
  • 33
  • 46
  • This doesn't work as expected because it exits if you close a frame and does not wait until the last frame is closed. But of course, all the threads and runnables aren't necessary. – kelunik May 15 '13 at 19:15
  • @Recode you are right. I changed it to DISPOSE_ON_CLOSE and it works. Note also the use of an `ActionListener` which is preferred over `MouseListener` for a button click. – wolfcastle May 15 '13 at 19:29
  • yeah, it's right, using an `ActionListener` is the common way for button-clicks. But I'm not sure if this program exits on the last window closed. – kelunik May 15 '13 at 19:36
  • I tested it, and it exits for me. Normally once all the displayable Swing/AWT components are gone (and there are no other threads), the VM will exit, but it's not guaranteed. Different JVMs may behave differently. – wolfcastle May 15 '13 at 19:47