Link to home
Start Free TrialLog in
Avatar of AttilaB
AttilaB

asked on

Threading issue - Unable to dispose of Window running in a separate thread

This would be a model of a larger application, that doesn't work either. Actually it is not fully accurate as a model
because instead of the timer I run a Windows executable in the 'real' app that returns a value and that will give the delay, not a timer. If I have any further trouble after solving it at this level - with the timer - I may post another one
I just don't even know if I can get the particular exe running without its environment and returning any value I can use in my Java program, for the demo.

So, for now if you start SelectProject where the main() method is,  then it will start a MainScreenMini3.java instance.
When you press the button both the timer starts and an instance of HourGlassWindow.java is created.
Which is essentially just a JWindow containing the animated gif 'HourGlass1.gif'.

When you press the button again the timer stops, but I don't seem to be able to create an interrupt to
the hourglass window thread that will dispose of my running HourGlassWindow.java instance.
So that when the next time the button is pushed a new instance of the hourglass window is created,
relative to the current position of the MainScreenMini3.java JFrame instance on the screen, so that it
occupies the same area over this JFrame, on top of the JFrame.

So this is how it looks, when running:
User generated image
And the 3 classes necessary:

1.  SelectProject.java, which will just pick a folderon your c:\ root and pass the path down to MainScreenMini3.java:
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class SelectProject extends JFrame {
	
	// Variables declaration 
	private JLabel jlblSelectTest;
	private JScrollPane scrollPane1;
        private DefaultListModel model; 
	private JList jlstProjectList;
	private JButton jbtnOpenProject;
	// End of variables declaration 
        
        private String selectionLine = "";
        
        // Class level declare instance of child window
        private MainScreenMini3 mainScreenMini3;
        
        
	public SelectProject() {
	   super("BST Program ITC version 1.1 - Select Project" ); 
	        initComponents();
	    try {
	        // Set the look and feel for the current OS (Windows) Scheme
	        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
	                initComponents();
            } catch (Exception e) {
                e.printStackTrace();
	                    }
            this.setSize(388,380);
	    this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
	}

	private void initComponents() {
		// Component initialization 
		jlblSelectTest = new JLabel();
		scrollPane1 = new JScrollPane();
                model = new DefaultListModel();
                jlstProjectList = new JList(model);
                
		jbtnOpenProject = new JButton();

		//======== this ========
		Container contentPane = getContentPane();
		contentPane.setLayout(null);

		//---- jlblSelectTest ----
		jlblSelectTest.setText("Select Test Project to Open:");
		jlblSelectTest.setFont(new Font("Tahoma", Font.BOLD, 14));
		jlblSelectTest.setHorizontalAlignment(SwingConstants.CENTER);
		contentPane.add(jlblSelectTest);
		jlblSelectTest.setBounds(50, 10, 260, 25);

		//======== scrollPane1 ========
		{
			scrollPane1.setViewportView(jlstProjectList);
		}
		contentPane.add(scrollPane1);
		scrollPane1.setBounds(20, 45, 340, 245);

		//---- jbtnOpenProject ----
		jbtnOpenProject.setText("Open Project");
		jbtnOpenProject.setFont(new Font("Tahoma", Font.BOLD, 12));
		jbtnOpenProject.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				jbtnOpenProject_ActionPerformed(e);
			}
		});
		contentPane.add(jbtnOpenProject);
		jbtnOpenProject.setBounds(125, 305, 120, jbtnOpenProject.getPreferredSize().height);

		{ // compute preferred size
			Dimension preferredSize = new Dimension();
			for(int i = 0; i < contentPane.getComponentCount(); i++) {
				Rectangle bounds = contentPane.getComponent(i).getBounds();
				preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
				preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
			}
			Insets insets = contentPane.getInsets();
			preferredSize.width += insets.right;
			preferredSize.height += insets.bottom;
			contentPane.setMinimumSize(preferredSize);
			contentPane.setPreferredSize(preferredSize);
		}
		pack();
		setLocationRelativeTo(getOwner());
            
	    // Add a list selection listener anonymous instance to JList control:
            // (implementing valueChanged() method)
	                     ListSelectionListener lListener = new ListSelectionListener() {
	                         public void valueChanged(ListSelectionEvent e) {
	                             if (e.getValueIsAdjusting() == false) // it will prevent double firing when  valueChanged() is called
	                             {
	                                 JList list = (JList) e.getSource();
	                                 if (!(list.isSelectionEmpty())) {
	                                     selectionLine = (String) list.getSelectedValue();

	                                     System.out.println("Selected: " + selectionLine);
	                                     
	                                 }
	                             }
	                         }
	                     };

	                     jlstProjectList.addListSelectionListener(lListener);
                
         listFoldersInFolder("C:\\");
	        
		// End of component initialization  
	}
        
        
        
    public static void main(String[] args) {
          
                  // The static utility method invokeLater(Runnable) is intended to execute a new runnable
                  // thread from a Swing application without disturbing the normal sequence of event dispatching
                  // from the GUI.
          
       SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                 try {
                                     // Set the look and feel for the current OS (Windows) Scheme and
                                     // all subsequent jFrames will also have the same look and feel
                                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                                     SelectProject selectProject = new SelectProject();
                                     selectProject.setLocationRelativeTo(null);
                                     
                                 } catch (Exception e) {
                                     e.printStackTrace();
                                 }
                            }
                        });
                  }  
      

    private void jbtnOpenProject_ActionPerformed(ActionEvent e) {
            System.out.println("Open project Button Clicked");
            if (selectionLine.equals("")){
                    JOptionPane.showMessageDialog(null, "       Select project to load ", "No Selection Made", JOptionPane.WARNING_MESSAGE);
                }
            else{
                    System.out.println("Open project: " + selectionLine);
                    // Creating Child Window Instances:
                    mainScreenMini3 = new MainScreenMini3(this, 0, selectionLine);
                    getChildMainScreenMini3();
                    this.setVisible(false);
                    mainScreenMini3.setVisible(true);  
                }
    }
    
    
    public void listFoldersInFolder(String pathName)
       {
           model.clear();
           File [] paths;
           File file=new File(pathName);
           if(file.isDirectory()){
             paths = file.listFiles();  
                for (int i=0; i<paths.length; i++)
                {
                    if (paths[i].isDirectory()){
                    System.out.println(paths[i].getPath());
                    
                    model.addElement(paths[i].getName());
                    }
                }
           }
       }
    
    // Returning an instance of the child window:
    private MainScreenMini3 getChildMainScreenMini3(){
        return mainScreenMini3;
    }

}

Open in new window


The mainScreenMini3 JFrame, that has the button:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;

public class MainScreenMini3 extends JFrame {
    
    private JLabel jlblTextLabel;
    private JButton jbtnStartTesting;
    private JScrollPane scrollPane1;
    private JList list1;
    
    Timer timer;  // Declare timer for class scope

    private int timerCount;  // Declare here for class scope
    private int timerPeriod = 1;  // Default 1 second period
    private boolean timerRunning = false;
    
    // Declarations needed for child window frame:
            SelectProject parent;
            int num;
    // End of Declarations needed for child window frame
            
            // Name of the selected test inside network test folder
            public String selectedTest = "";
            
    private HourGlassWindow hourGlassWindow;
    private Thread hourGlassThread;
    
	public MainScreenMini3(SelectProject parent, int num, String folderSelected) {  // Constructor for creating JFrame as Child Window 
            
	    this.parent = parent;
            this.num = num;
            
            System.out.println("Selected Folder: " + folderSelected);
            
            // Initialize folder name of test selected:
            this.selectedTest = folderSelected;
            
		initComponents();
                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                this.setResizable(false);
	}

	private void initComponents() {
		// Component initialization 
		jlblTextLabel = new JLabel();
		jbtnStartTesting = new JButton();
		scrollPane1 = new JScrollPane();
		list1 = new JList();
                
	    // inner class listener for Standard test button:
	           jbtnStartTesting.addActionListener(new ActionListener() {
	               public void actionPerformed(ActionEvent evt) {
	                   jbtnStartTesting_ActionPerformed(evt);
	               }
	           });

		//======== this ========
		Container contentPane = getContentPane();
		contentPane.setLayout(null);

		//---- jlblTextLabel ----
		jlblTextLabel.setText("Not Tested");
		jlblTextLabel.setFont(new Font("Tahoma", Font.BOLD, 22));
		jlblTextLabel.setHorizontalAlignment(SwingConstants.CENTER);
		contentPane.add(jlblTextLabel);
		jlblTextLabel.setBounds(115, 30, 150, 50);

		//---- jbtnStartTesting ----
		jbtnStartTesting.setText("Start Testing");
		jbtnStartTesting.setFont(new Font("Tahoma", Font.PLAIN, 18));
		contentPane.add(jbtnStartTesting);
		jbtnStartTesting.setBounds(115, 75, 150, 65);

		//======== scrollPane1 ========
		{
			scrollPane1.setViewportView(list1);
		}
		contentPane.add(scrollPane1);
		scrollPane1.setBounds(25, 150, 340, scrollPane1.getPreferredSize().height);

		{ // compute preferred size
			Dimension preferredSize = new Dimension();
			for(int i = 0; i < contentPane.getComponentCount(); i++) {
				Rectangle bounds = contentPane.getComponent(i).getBounds();
				preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
				preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
			}
			Insets insets = contentPane.getInsets();
			preferredSize.width += insets.right;
			preferredSize.height += insets.bottom;
			contentPane.setMinimumSize(preferredSize);
			contentPane.setPreferredSize(preferredSize);
		}
    
		pack();
		setLocationRelativeTo(getOwner());
		
	}
        
    // Action Listener for  button:
       private void jbtnStartTesting_ActionPerformed(ActionEvent evt) {
           System.out.println("Button Pressed");
           
           timerCount = 0;
                  
                  if (timerRunning == false){
                      timer = new Timer();  // This will start timer (!)
                      timerRunning = true;    // change it to opposite
                      jbtnStartTesting.setText("Stop Test");
                      
                      timer.scheduleAtFixedRate(new LoopTask(),      // Use scheduleAtFixedRate method when time synchronization is more important                         
                                    0,        //initial delay
                                   timerPeriod * 1000);  //subsequent rate (milliseconds)  
                      
                  }
                  else
                  {
                      timerRunning = false;  // change it to opposite
                      jbtnStartTesting.setText("Start Test");
                      timer.cancel(); // Stop timer
                     
                      // ????????????????????????????????????????????????????
                      // Interrupt the thread to generate an exception in the
                      // HourGlassWindow class instance, never works:
                      hourGlassThread.interrupt();
                      hourGlassWindow = null;
                      
                      timerCount = 0;
                      
                      // ?????????????????????????????????????????????????????
                      // This will never update the screen:
                      jlblTextLabel.setText("<html><font color = red>DONE</font></html>");
                      
                      System.out.println("Timer Stopped.");  // This will show up
                       
                  }
           
           // Create HourGlassWindow instance
           hourGlassWindow = new HourGlassWindow(this);
           hourGlassThread = new Thread(hourGlassWindow);
           hourGlassThread.start();
           hourGlassWindow.setAlwaysOnTop(true);
           hourGlassWindow.setSize(134,142);
            
           // Set the location of the hourglass relative to the CasconMainScreen
           // location on the screen:
           Point pointOfLocation = this.getLocationOnScreen();
           pointOfLocation.setLocation(pointOfLocation.getX()+210,pointOfLocation.getY()+207);
           hourGlassWindow.setLocation(pointOfLocation); 
           hourGlassWindow.setVisible(true);
           
           jlblTextLabel.setText("<html><font color = black>TESTING</font></html>");
           
       }
       
    // LoopTask is an inner class, implementing TimerTask class run() method:
           class LoopTask extends TimerTask {

               public void run() {
                       System.out.println("Run timed method");
                       timerCount++;
                       System.out.println(Integer.toString(timerCount));
                   }
               }   
       
}

Open in new window


And the hourglass window:
import java.awt.*;
import javax.swing.*;

public class HourGlassWindow extends JWindow implements Runnable{
    
    private Icon iconImage = new ImageIcon(getClass().getResource("icons/HourGlass1.gif"));
    private JLabel jlblHourGlassImage;
    private MainScreenMini3 parent;
    
    private HourGlassWindow hourGlassWindow; 

	public HourGlassWindow(MainScreenMini3 parent) {
		initComponents();
	}

	private void initComponents() {
		jlblHourGlassImage = new JLabel();

		//======== this ========
		Container contentPane = getContentPane();
		contentPane.setLayout(null);

		//---- jlblHourGlassImage ----
		jlblHourGlassImage= new JLabel(iconImage, JLabel.CENTER); // Creating  the jLabel for the image
		jlblHourGlassImage.setHorizontalAlignment(SwingConstants.CENTER);
		contentPane.add(jlblHourGlassImage);
		jlblHourGlassImage.setBounds(10, 10, 105, 100);

		{ // compute preferred size
			Dimension preferredSize = new Dimension();
			for(int i = 0; i < contentPane.getComponentCount(); i++) {
				Rectangle bounds = contentPane.getComponent(i).getBounds();
				preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
				preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
			}
			Insets insets = contentPane.getInsets();
			preferredSize.width += insets.right;
			preferredSize.height += insets.bottom;
			contentPane.setMinimumSize(preferredSize);
			contentPane.setPreferredSize(preferredSize);
		}
		pack();
		setLocationRelativeTo(getOwner());
		// JFormDesigner - End of component initialization  //GEN-END:initComponents
	}
    
        
    public void run(){
        try{
            hourGlassWindow = new HourGlassWindow(parent);
            
        }
        
     
     // Cannot get this to compile:   ?????????????????????
  /*      catch(InterruptedException e){
            System.err.println();
        }
*/
    
        catch(Exception e){
            System.err.println();
             hourGlassWindow.dispose();  // Not Working ?????
             hourGlassWindow = null;   // Not Working ?????
        }
    }

}

Open in new window


And finally, I need to give you the animated GIF image for the hourglass, as an attached file.

What am I doing wrong here?

Thanks.
HourGlass1.gif
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));

Open in new window


from someplace that holds a reference to 'frame'.
Hi,
Here is an approach

while(!Thread.currentThread().isInterrupted)
    {
      .........
    }
Well that code won't compile as it is, but even so, how does it dispose of the JFrame, once the thread would be interrupted? The loop you suggest looks redundant to me.
Avatar of AttilaB
AttilaB

ASKER

Hi, thanks for looking at it.
hourGlassWindow.dispatchEvent(new WindowEvent(hourGlassWindow, WindowEvent.WINDOW_CLOSING));

Open in new window


This will compile, but will not do anything. The other one with the loop will not compile.

If you make a project out of the 3 classes, make a folder inside the classes folder and copy the GIF file into 'icons/HourGlass1.gif' you can try it yourselves. My files compile and run, as seen in screen shot I just cannot get rid of the hourglass JWindow instance once it has been created.

You could try your suggestions right in there.  Thanks.
Ok so can you first try to set the hourGlassWindow to null when you no longer need it.

(For some reason I thought your original container was a JFrame).
Avatar of AttilaB

ASKER

Well, the hourglass window is a JWindow. Where I want to stop it  from is a JFrame.

So, I did one thing dumb, that I also creared a new instance by putting the instance creation in the wrong place. With the right place, it still not working, even though the code is running with no compile or run-time errors.

User generated image
The updated code for this one class, MainScreenMini3 JFrame, that I changed now:

;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;

import java.util.Timer;
import java.util.TimerTask;
import javax.swing.*;

public class MainScreenMini3 extends JFrame {
    
    private JLabel jlblTextLabel;
    private JButton jbtnStartTesting;
    private JScrollPane scrollPane1;
    private JList list1;
    
    Timer timer;  // Declare timer for class scope

    private int timerCount;  // Declare here for class scope
    private int timerPeriod = 1;  // Default 1 second period
    private boolean timerRunning = false;
    
    // Declarations needed for child window frame:
            SelectProject parent;
            int num;
    // End of Declarations needed for child window frame
            
            // Name of the selected test inside network test folder
            public String selectedTest = "";
            
    private HourGlassWindow hourGlassWindow;
    private Thread hourGlassThread;
    
	public MainScreenMini3(SelectProject parent, int num, String folderSelected) {  // Constructor for creating JFrame as Child Window 
            
	    this.parent = parent;
            this.num = num;
            
            System.out.println("Selected Folder: " + folderSelected);
            
            // Initialize folder name of test selected:
            this.selectedTest = folderSelected;
            
		initComponents();
                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                this.setResizable(false);
	}

	private void initComponents() {
		// Component initialization 
		jlblTextLabel = new JLabel();
		jbtnStartTesting = new JButton();
		scrollPane1 = new JScrollPane();
		list1 = new JList();
                
	    // inner class listener for Standard test button:
	           jbtnStartTesting.addActionListener(new ActionListener() {
	               public void actionPerformed(ActionEvent evt) {
	                   jbtnStartTesting_ActionPerformed(evt);
	               }
	           });

		//======== this ========
		Container contentPane = getContentPane();
		contentPane.setLayout(null);

		//---- jlblTextLabel ----
		jlblTextLabel.setText("Not Tested");
		jlblTextLabel.setFont(new Font("Tahoma", Font.BOLD, 22));
		jlblTextLabel.setHorizontalAlignment(SwingConstants.CENTER);
		contentPane.add(jlblTextLabel);
		jlblTextLabel.setBounds(115, 30, 150, 50);

		//---- jbtnStartTesting ----
		jbtnStartTesting.setText("Start Testing");
		jbtnStartTesting.setFont(new Font("Tahoma", Font.PLAIN, 18));
		contentPane.add(jbtnStartTesting);
		jbtnStartTesting.setBounds(115, 75, 150, 65);

		//======== scrollPane1 ========
		{
			scrollPane1.setViewportView(list1);
		}
		contentPane.add(scrollPane1);
		scrollPane1.setBounds(25, 150, 340, scrollPane1.getPreferredSize().height);

		{ // compute preferred size
			Dimension preferredSize = new Dimension();
			for(int i = 0; i < contentPane.getComponentCount(); i++) {
				Rectangle bounds = contentPane.getComponent(i).getBounds();
				preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
				preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
			}
			Insets insets = contentPane.getInsets();
			preferredSize.width += insets.right;
			preferredSize.height += insets.bottom;
			contentPane.setMinimumSize(preferredSize);
			contentPane.setPreferredSize(preferredSize);
		}
    
		pack();
		setLocationRelativeTo(getOwner());
		
	}
        
    // Action Listener for  button:
       private void jbtnStartTesting_ActionPerformed(ActionEvent evt) {
           System.out.println("Button Pressed");
           
           timerCount = 0;
                  
                  if (timerRunning == false){
                      
                      // Create HourGlassWindow instance
                      hourGlassWindow = new HourGlassWindow(this);
                      hourGlassThread = new Thread(hourGlassWindow);
                      hourGlassThread.start();
                      hourGlassWindow.setAlwaysOnTop(true);
                      hourGlassWindow.setSize(134,142);
                       
                      // Set the location of the hourglass relative to the CasconMainScreen
                      // location on the screen:
                      Point pointOfLocation = this.getLocationOnScreen();
                      pointOfLocation.setLocation(pointOfLocation.getX()+210,pointOfLocation.getY()+207);
                      hourGlassWindow.setLocation(pointOfLocation); 
                      hourGlassWindow.setVisible(true);
                      
                      jlblTextLabel.setText("<html><font color = black>TESTING</font></html>");
                      
                      timer = new Timer();  // This will start timer (!)
                      timerRunning = true;    // change it to opposite
                      jbtnStartTesting.setText("Stop Test");
                      
                      timer.scheduleAtFixedRate(new LoopTask(),      // Use scheduleAtFixedRate method when time synchronization is more important                         
                                    0,        //initial delay
                                   timerPeriod * 1000);  //subsequent rate (milliseconds)  
                      
                  }
                  else
                  {
                      timerRunning = false;  // change it to opposite
                      jbtnStartTesting.setText("Start Test");
                      timer.cancel(); // Stop timer
                     
                      // ????????????????????????????????????????????????????
                      // Interrupt the thread to generate an exception in the
                      // HourGlassWindow class instance, never works:
                      
                      
                      hourGlassWindow.dispatchEvent(new WindowEvent(hourGlassWindow, WindowEvent.WINDOW_CLOSING));
                      hourGlassThread.interrupt();
                      hourGlassWindow = null;

                      timerCount = 0;
                      jlblTextLabel.setText("<html><font color = red>DONE</font></html>");
                      System.out.println("Timer Stopped.");  // This will show up   
                  }
       }
       
       
    // LoopTask is an inner class, implementing TimerTask class run() method:
           class LoopTask extends TimerTask {

               public void run() {
                       System.out.println("Run timed method");
                       timerCount++;
                       System.out.println(Integer.toString(timerCount));
                   }
               }   
       
}

Open in new window


The other 2 classes are unchanged, as I gave you previously. Sorry about that.
See, it is running, but not executing making the instance null.
Here is a simple model :

import javax.swing.*;
import java.awt.*;

class JF extends JFrame{

static JWindow w;

public static void main(String[] args){

	JF jf = new JF();

	jf.setVisible(true);

	jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);


	try{

		Thread.sleep(3000);
		w.setVisible(false);

	}catch(Exception e){}

	w=null;

	
	try{

		Thread.sleep(3000);
		w.setVisible(false);

	}catch(Exception e){}
	
	w = new JWindow(jf);w.setSize(new Dimension(100,200));w.setVisible(true);


}

public JF(){w = new JWindow(this);w.setSize(new Dimension(100,200));w.setVisible(true);}


}

Open in new window


This gives a JFrame that owns a JWindow, which is shewn, nullified, and re-instantiated again. Hope this helps.
Avatar of AttilaB

ASKER

I suspect the solution is with making the interrupt() method of the new thread running the JWindow instance working. I cannot make the code to have the catching of the interrupt exception compile!  I put a catch-all in there that doesn't do a thing. I don't think you can make a new thread stop without interrupting it. But how?
I fully admit that I have not looked at your code and have not tried to run it.

But I don't think the appearance or existence of the JWindow - (hourGlass) - has anything much to do with a thread. You should be able to get rid of the JWindow completely at will, independently of any thread running. Try running my class above, and see the effect on the child JWindow.

(By the way, if you run the code I gave, get rid of line 30 of course - it was a copy and paste oversight, and shouldn't be there).
Avatar of AttilaB

ASKER

Krakatoa, your code compiles and runs fine, I just don't see how it can help me with interruption of a running thread at will, when something happens not relating to the running timer (like in my case I push the button again.) The timer is running, parallel in my case with the JWindow instance, after the first push, when I push it the second time, the timer stops fine. The instance of the JWindow cannot be killed though at that point. All the code after my attempt to kill the JWindow thread executes fine, the program doesn't crash, just the JWindow stays
no matter what. That's my problem.
Avatar of AttilaB

ASKER

I think we are a little out of sync here with the posts, but if the existence of jWindow has not much to do with
the thread, how come setting it to null will not make it disappear?
Well your code uses hourGlass*** terms frequently and I'm going cross-eyed. Try pointing at hourGlassWindow via hourGlassThread, so  :

hourGlassThread.hourGlassWindow.dispose();
Avatar of AttilaB

ASKER

I cannot really put 'setvisible(false)' here in the program regarding the JWindow instance. If I do, then the program will create 500 invisible instances all over the screen if the user moves the JFrame and the test is run 500 times in the original program. If they don't move the JFrame then on top of each other. Maybe, I could jerry-rig it up with a single instance I ever create, that I just turn off visibility and turn on, as needed. Then each time I calculate the proper location in the screen before turning on visibility. That could be a solution. I just thought if I put something like a JWindow up on the screen I should be able to make it go away to nothing or null, without closing the main class instance running.

If not, I may just have to jerry-rig it with a hidden / visible instance automatically moved around in the screen.
Avatar of AttilaB

ASKER

Sorry about the naming. You may rename anything to anything else, just tell me what / give me the code.

hourGlassThread.hourGlassWindow.dispose(); 

Open in new window


This will NOT compile unfortunately. I will tell you what will work getting rid of the instance and compile and seems to run fine, though:

                      hourGlassThread.stop();
                      hourGlassWindow.dispose();

Open in new window


BUT! This is deprecated code, crossed out by the compiler. Not supposed to be used.

I think if you can tell me how I can generate a thread interrupt and capture the InterruptedException so that it compiles, we got it going.
Can't you just make hourGlassWindow a member of hourGlassThread?
As to your last comment - threads as you rightly state, are not stopped by stop(). The convention is more to have a boolean flag as the terminal condition of run() so it can be set to false, and let run() exit softly.
Avatar of AttilaB

ASKER

Your last too comments are very interesting 'make hourGlassWindow a member of hourGlassThread' and also to
'have a boolean flag as the terminal condition of run() so it can be set to false, and let run() exit softly' this is new
to me. I am not sure how I would do either. How does a thread 'exit softly' if setting it to null doesn't kill it?
With or without a flag.
Could you modify that section in my program to reflect?
SOLUTION
Avatar of krakatoa
krakatoa
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I cannot really put 'setvisible(false)' here in the program re . . .

I didn't say only that though, if you look - the code then sets the jwindow instance to *null*. That's why when you run that code I posted, you'll see a second JWindow come up again on the JFrame, using the same var name.
Avatar of AttilaB

ASKER

I fixed that,  that was just a dumb mistake:  the new window instance coming up in the code, then  I re-posted the code of the JFrame without the issue in the posting '2015-02-24 at 11:04:35' earlier today.

Ok. I will do what you recommended:

public void run(){

while(truth){
 //doThings();
}

this approach you are telling me later on today, and will let you know.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of AttilaB

ASKER

Well actually I combined krakatoa's suggestion and mccarl's suggestion and made it work, as follows:

private boolean keepRunning = true;   // at the beginning of the class, class level

.......................


    public void run(){
    
        try{
            
            if(keepRunning){
                hourGlassWindow = new HourGlassWindow(parent); 
                keepRunning = false;
            }
            else
                hourGlassWindow.dispose();
                keepRunning = true;
            }
    
        catch(Exception e){
            System.err.println();
        
        }
    }

Open in new window


I made the boolean private, because it is not accessed anywhere outside the class. Instead of using while I used if. Honestly, I did not expect this to work. That only shows that I have trouble understanding multi-threaded programs. I got a couple of books with a chapter each on this, I am going to read it over the weekend.

Any suggestions on good books on this, or good examples?

mccarl, actually I found that dumb mistake about the multiple instances, and uploaded the revised code earlier.
You must have been looking at the first version I uploaded.

I fully agree with you, now that I apply it to the 'full-fledged' program it may or may not work, and I may be forced
to post another question a little more targeted to my original problem.

Thanks, guys.
Good that you have it working. I am not quite sure however that the boolean I was talking about has been applied quite as I was suggesting  - the boolean should determine whether the run() method keeps repeating its routines, and therefore stays alive. But what you have done is to make a single pass through run(), and dispose of the JWindow based on the boolean, which is quite different because you could do that more simply by asking if the JWindow itself was still resident.

Anyway, mccarl is very likely to be able to say a great deal more than I on all this, but good luck. As for books etc., I'd recommend asking questions here on EE - because getting the fundamentals of OOP Java programming explained well, is what the site is good at. ;)
mccarl, actually I found that dumb mistake about the multiple instances, and uploaded the revised code earlier.
You must have been looking at the first version I uploaded
No, I *was* looking at your updated code! And your are still creating multiple instances of HourGlassWindow. In your updated MainScreenMini3.java code (posted in this comment) on line 117 you are creating an instance. Then in either your old OR new versions of HourGlassWindow.java on line 11 of your new code posted just above or on line 50 of the code in the initial question you are creating another instance. As I said this second one that you are creating inside the Thread is not doing anything useful anyway, because it never gets displayed (there's no .setVisible(true) call on THIS instance).

And as krakatoa has already pointed out above, your thread is not doing anything useful either. The thread starts and your run() method gets called, in there you are creating the instance of HourGlassWindow (that doesn't do anything, as per above), then you set the boolean to false (which also means nothing because it will never again get checked in this thread) and then your run method end. At which point your thread ends, ie. it stops executing, never to be run again (until you create a new instance of the thread anyway).

Now threads ARE tricky and there is a fair amount of concepts to get your head around if you want to fully understand them. I don't personally know of any books that might help (the internet generally provides all the info that I need) but I do know that a lot of people recommend Java Concurrency in Practice. Also I would recommend having a look at some online tutorials; I've always thought the Sun/Oracle tutorials aren't too bad, such as Concurrency Tutorial.
Avatar of AttilaB

ASKER

Thanks for the advice and recommendations. I downloaded the PDF and looked at the Oracle tutorial and they look quite useful.
You're welcome, and good luck! ;)