Stop old Thread when a new one will be initialized

Hi

I got several Threads:
one to Listen the Joystick input and fire an event when a significant change was detected, works very good with jinput.
the other one is a swing jFrame shown for several seconds when a event was fired.

The basic was my app does is listen to the joystick -> execute a action and displays a JFrame what happend.

I dont wanna that 2 JFrames show up at the same time, when a new JFrame should be opened the older one should dispose before the new one shows up.

...
while(queue.getNextEvent(event)) {
		StringBuffer buffer = new StringBuffer();
		Component comp = event.getComponent();
		JoyStickAction.action(comp, event.getValue());
}
...

the joystick listener executing the action class

...
if(display_window) {
            new DisplayInfo("title", window_text, 250, 50, 1000).start();
}
...

at the end of the action class

DisplayInfo is the class that opens the JFrame I wanna close when already a instance was createt

import javax.swing.*;
import java.awt.*;
public class DisplayInfo extends Thread {
    //title and text
    String title;
    String text;

    //size in pixels
    int width = 400;
    int height = 100;

    //time to display in ms
    int time = 3000;

    //class infos
    static int instances = 0;
    static DisplayInfo instance;

    public DisplayInfo(String title, String text, int width, int height, int time) {
        if(instances>0) {
            instance.stopInstance();
        }
        ++instances;
        instance = this;
        this.title = title;
        this.text = text;
        this.width = width;
        this.height = height;
        this.time = time;
    }

    public void run() {
        //Create and set up the window.
        JFrame frame = new JFrame(title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setUndecorated(true); //removes the borders

        //add text to the frame
        JLabel label = new JLabel(instances+" - "+text, JLabel.CENTER);
        label.setForeground(new Color(0xBB, 0xBB, 0xBB));
        frame.getContentPane().add(label);

        //set size
        frame.setSize(width, height);

        //get screen size
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenSize = toolkit.getScreenSize();

        //Calculate the frame location
        int x = (screenSize.width - frame.getWidth()) / 2;
        int y = ((screenSize.height - frame.getHeight()) / 3) * 2;

        //color
        frame.getContentPane().setBackground(new Color(0x33, 0x33, 0x33));

        //Display the window.
        frame.setLocation(x ,y);
        frame.setVisible(true);

        //wait
        try {
            Thread.currentThread().sleep(time);
        } catch(InterruptedException ie) { }
        //close
        frame.dispose();
    }

    public void stopInstance() {
        --instances;
        this.stop();
    }
}

I already tested something with instance counting and trying to close the old one but that wont work.
Probably the the thread wont be passed by reference to “instance”?
It’s the way I would do it in PHP :slight_smile:

How could I get it work?

Hopefully you understand what I wanna say…

Maybe you can alter your code somewhat like this.

At the end of your action class.


if(display_window) {
    if(this.displayInfo != null && this.displayInfo.isAlive()) {
        this.displayInfo.getFrame().dispose();
    }

    this.displayInfo = new DisplayInfo("title", window_text, 250, 50, 1000);
    this.displayInfo.start();
}

Also make sure you add a new member to that class called displayInfo which is of type DisplayInfo.

You will also need to modify your DisplayInfo class and add a reference to the created JFrame.

import javax.swing.*;
import java.awt.*;
public class DisplayInfo extends Thread {
    //title and text
    String title;
    String text;

    //size in pixels
    int width = 400;
    int height = 100;

    //time to display in ms
    int time = 3000;

    // The frame
    JFrame frame;

    //class infos
    static int instances = 0;
    static DisplayInfo instance;

    public DisplayInfo(String title, String text, int width, int height, int time) {
        if(instances>0) {
            instance.stopInstance();
        }
        ++instances;
        instance = this;
        this.title = title;
        this.text = text;
        this.width = width;
        this.height = height;
        this.time = time;
    }

    public void run() {
        //Create and set up the window.
        this.frame = new JFrame(title);
        this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.frame.setUndecorated(true); //removes the borders

        //add text to the frame
        JLabel label = new JLabel(instances+" - "+text, JLabel.CENTER);
        label.setForeground(new Color(0xBB, 0xBB, 0xBB));
        this.frame.getContentPane().add(label);

        //set size
        this.frame.setSize(width, height);

        //get screen size
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenSize = toolkit.getScreenSize();

        //Calculate the frame location
        int x = (screenSize.width - frame.getWidth()) / 2;
        int y = ((screenSize.height - frame.getHeight()) / 3) * 2;

        //color
        this.frame.getContentPane().setBackground(new Color(0x33, 0x33, 0x33));

        //Display the window.
        this.frame.setLocation(x ,y);
        this.frame.setVisible(true);

        //wait
        try {
            Thread.currentThread().sleep(time);
        } catch(InterruptedException ie) { }

        //close
        this.frame.dispose();
    }

    public void stopInstance() {
        --instances;
        this.stop();
    }

    public JFrame getFrame() {
        return this.frame;
    }
}

Now that will give you a solution for closing the actual frame and the thread should die automatically after your set time anyway. However you might want to consider implementing Runnable instead of extending thread and also adding a boolean with a while loop in the run method because thread.stop() has been deprecated.

// Json

I implemented like you postet it.

A small problem the

if(display_window) {
    if(this.displayInfo != null && this.displayInfo.isAlive()) {
        this.displayInfo.getFrame().dispose();
    }

wont be executed, as well there is another frame/instance…
I cant see the problem on my code!

I attached my complete code :wink:
with ./b I compile it and with ./r I run it, its linux only (the Jinput plugin is only included with linux sources…) :wink:

EDIT:/
my ass, why I cant upload a zip file?
You can find my code here -> http://www.rrelmy.ch/code.zip

So just have one!


if(display_window) {
            new DisplayInfo("title", window_text, 250, 50, 1000).start();
}

This is bad practice as you’re creating a self-governing entity (ie, you have no control over it).
How about;


DisplayInfo currentDisplayInfo=null;
...
if(display_window) {
            if (currentDisplayInfo!=null && currentDisplayInfo.isAlive()) {
                    currentDisplayInfo.dispose();
            }    
            currentDisplayInfo=new DisplayInfo("title", window_text, 250, 50, 1000);
            currentDisplayInfo.start();
}

Maybe you should try and take another approach and not use a separate thread. You could just initialise a frame and keep it referenced and whenever you get a joystick action you set the labels and whatnot on the frame and then you make it visible. Once the 1 second time limit is up you hide the window and start all over. If there is a new action while the window is already open, just reset the timer and change the information in the window.

// Json

Thanks you guys, it works :smiley:

I store the JFrame and the JLabel in a static variable and “hide -> update -> show” the JFrame whitout create a new one.

next step: semi transparent JFrame :smiley:

Brilliant :smiley:

// Json