Painting problem

capture
Tags: #<Tag:0x00007fd546e510f0>

#1

Hi there,

i’m facing a disturbing problem for my plugin.
I tried to make a simplified version of my problem with the source code attached here.

In my plugin I take an imageplus to let the user make ROIs (and the plugin calculate some parameters) and take a secondary capture of the window.

My problem is : after a secondary capture Fiji/ImageJ seems to be frozen unless the program stops to wait for an user action.

In my program sometimes I do not need any user action, so I have a code which set a slice, take a capture, change slice number and take a second capture (also add an remove overlay…)

If I don’t give user action the painting is not made. I tried to force the painting with various methods (update, draw…) without result.

In the code in attachment you will see the simplified version of my plugin, it create a custom windowstack from an imageplus input and you have a “Capture” button to see the problem.

I add a IJ.wait after trying to display the screen capture capture, you will see that the new imageplus window is created but the image is not displayed until the end of the wait (which is the end of the program until a new user action).

I may forgot something or it may be an ImageJ bug.
If it is a normal behavior what is the correct way to force and get the painting to be able to run other automatic operation on the display and take new captures from the painted window ?

This project is to build nuclear medicine applications as part of our free and open source project for PET/CT.
As we are in the first steps for this nuclear medicine project it is really important for us to debug this problem (the same structure will be used for all next programs)

Thanks for your help,

Salim

import java.awt.AWTException;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map.Entry;

import fiji.util.gui.OverlayedImageCanvas;
import ij.IJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.ImageCanvas;
import ij.gui.ImageWindow;
import ij.gui.StackWindow;
import ij.gui.Toolbar;
import ij.plugin.PlugIn;
import ij.util.DicomTools;

public class Vue_Shunpo implements PlugIn {


	protected HashMap<String, ButtonlesBoutons;

	private boolean imageOuverte = false;

	private Label img_inst;

	protected static ImagePlus imp;
	
	@Override
	public void run(String arg) {
		this.init();
	}
	
	private void init() {
		// Initialisation des différents attributs
		this.img_inst = new Label();
		initBoutons(); 
		this.lesBoutons.get("Valider").addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				Button b = (Button) arg0.getSource();
				if (WindowManager.getCurrentImage() != null && Vue_Shunpo.this.imageOuverte == true) {
					ImagePlus imp=WindowManager.getCurrentImage();
					((Frame) b.getParent().getParent()).dispose();
					secondImage(imp) ;
				}
				if (WindowManager.getCurrentImage() != null && Vue_Shunpo.this.imageOuverte == false) {
					Vue_Shunpo.this.imageOuverte = true;
					ImagePlus imp=WindowManager.getCurrentImage();
					((Frame) b.getParent().getParent()).dispose();
					ouvertureImage(imp) ;
				}
				
			}

		});
		if (!this.imageOuverte)
			ouvrirImage("Lungs - Kidneys");

	}
	//Buttons initialisation
	private void initBoutons() {

		this.lesBoutons = new HashMap<>();
		this.lesBoutons.put("Restart", new Button(" Restart "));
		this.lesBoutons.put("Replace", new Button(" Replace "));
		this.lesBoutons.put("Capture", new Button(" Capture"));
		this.lesBoutons.put("Contrast", new Button(" Contrast "));
		this.lesBoutons.put("Précédent", new Button(" Previous "));
		this.lesBoutons.put("Suivant", new Button(" Next "));
		this.lesBoutons.put("New Window", new Button(" New Window "));
		this.lesBoutons.put("Valider", new Button(" Confirm "));
	}
	
	
	
	// CustomCanvas method
	class CustomCanvas extends OverlayedImageCanvas {

		private static final long serialVersionUID = -5710708795558320699L;

		CustomCanvas(ImagePlus imp) {

			super(imp);
		}
		
		public void mousePressed(MouseEvent e) {
		super.mousePressed(e);
		//IJ.log("mousePressed: ("+offScreenX(e.getX())+","+offScreenY(e.getY())+")");
		}
		
		} 
	

	// Custum stack method modified From: https://imagej.nih.gov/ij/plugins/panel-window.html
	
	class CustomStackWindow extends StackWindow implements ActionListener {

		private static final long serialVersionUID = -6280620624574294247L;

		CustomStackWindow(ImagePlus imp) {
			super(imp, new CustomCanvas(imp));
			addPanel();
			addEcouteurs();
			
		} // Fin constructeur CustomStackWindow

		// Construction de l'interface
		void addPanel() {
			// Agencement des composants
			Panel panel = new Panel();
			panel.setLayout(new FlowLayout());

			// Partie gauche
			Panel gauche = new Panel();
			gauche.setLayout(new FlowLayout());

			// Premiers boutons
			Panel btns_glob = new Panel();
			btns_glob.setLayout(new GridLayout(1, 3));
			btns_glob.add(Vue_Shunpo.this.lesBoutons.get("Capture"));
			btns_glob.add(Vue_Shunpo.this.lesBoutons.get("New Window"));
			btns_glob.add(Vue_Shunpo.this.lesBoutons.get("Replace"));
			gauche.add(btns_glob);

			// Instructions
			Panel instru = new Panel();
			instru.setLayout(new GridLayout(2, 1));
			Panel btns_instru = new Panel();
			btns_instru.setLayout(new GridLayout(1, 3));
			btns_instru.add(Vue_Shunpo.this.lesBoutons.get("Restart"));
			btns_instru.add(Vue_Shunpo.this.lesBoutons.get("Précédent"));
			btns_instru.add(Vue_Shunpo.this.lesBoutons.get("Suivant"));
			instru.add(btns_instru);
			instru.setBackground(Color.LIGHT_GRAY);
			gauche.add(instru);
			panel.add(gauche);
			add(panel);
			pack();

			// Permet d'avoir la fenêtre ouverte au même endroit que l'image
			// sélectionnée par l'utilisateur
			Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); 
			Point loc = getLocation();
			Dimension size = getSize();
			if (loc.y + size.height screen.height)
				getCanvas().zoomOut(0, 0);
		} // Fin addPanel
		
		private void addEcouteurs() {
			for (Entry<String, Buttonentry : Vue_Shunpo.this.lesBoutons.entrySet())
				entry.getValue().addActionListener(this);
		}
		//Controller here for actions
		public void actionPerformed(ActionEvent arg0) {
		Button b = (Button) arg0.getSource();
		if (b == Vue_Shunpo.this.lesBoutons.get("New Window")){
			screenShot(Vue_Shunpo.imp);
			IJ.wait(3000);
			IJ.showMessage("end");
		}
		if (b == Vue_Shunpo.this.lesBoutons.get("Replace")){
		ouvrirImage("second image");
			}
		if (b == Vue_Shunpo.this.lesBoutons.get("Suivant")){
		WindowManager.getCurrentImage().setSlice(1);
			}
		
		if (b == Vue_Shunpo.this.lesBoutons.get("Capture")){
			screenShot(Vue_Shunpo.imp);
			IJ.wait(5000);
				}
		}
		}

	
	// Opening dialog to select the imageplus to open (or replace) in the customstack
	protected void ouvrirImage(String image) {
		Frame f = new Frame();
		Panel pan = new Panel();
		pan.setLayout(new GridLayout(2, 1));
		Vue_Shunpo.this.img_inst.setText("Please open the " + image + " image then confirm.");
		pan.add(Vue_Shunpo.this.img_inst);
		pan.add(this.lesBoutons.get("Valider"));
		f.add(pan);
		f.setLocationRelativeTo(null);
		Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
		f.setSize(200, 300);
		f.setLocation(dim.width / 2 - f.getSize().width / 2, dim.height / 2 - f.getSize().height / 2);
		f.setVisible(true);
		f.setResizable(false);
		f.toFront();
		f.pack();
		
	}
	
	// create the custom window stack with the first imageplus
	private void ouvertureImage(ImagePlus imp) {
		
		int[] imageOriginale= imp.getDimensions();
		Vue_Shunpo.imp=imp;
		String tagSerie = DicomTools.getTag(imp, "0008,103E");
		CustomStackWindow win = new CustomStackWindow(imp);
		win.pack();
		win.setTitle(tagSerie);
		win.toFront();
		win.setSize((imageOriginale[1]*2)+12, (imageOriginale[1])*2+46+68+25);
		ImageCanvas cc=win.getCanvas();
		cc.fitToWindow();
		imp.setTitle(tagSerie);
		IJ.setTool(Toolbar.POLYGON);
	}

	
	// replace the previous imageplus by a new imageplus in the costum window
	protected void secondImage(ImagePlus imp) {
			//C'est la deuxieme image
			ImageWindow win =Vue_Shunpo.imp.getWindow();
			win.setImage(imp);
			win.toFront();
			int[] imageOriginale= imp.getDimensions();
			win.setSize((imageOriginale[1]*2)+12, (imageOriginale[1])*2+46+68+25);
			ImageCanvas cc=win.getCanvas();
			cc.requestFocus();
			cc.fitToWindow();
			IJ.wait(250);
			win.toFront();
			imp.deleteRoi();
			IJ.setTool(Toolbar.POLYGON);
	}
	
	
	//Screshoot methode taken from Screngrabber ij library
	public void screenShot(ImagePlus fen) {
	        ImageWindow win = imp.getWindow();
	        win.toFront();
	        IJ.wait(500);
	        Point loc = win.getLocation();
	        ImageCanvas ic = win.getCanvas();
	        Rectangle bounds = ic.getBounds();
	        loc.x += bounds.x;
	        loc.y += bounds.y;
	        Rectangle r = new Rectangle(loc.x, loc.y, bounds.width, bounds.height);
	        ImagePlus imp2 = null;
	        Image img = null;
	        boolean wasHidden = ic.hideZoomIndicator(true);
	        IJ.wait(250);
	        try {
	            Robot robot = new Robot();
	            img = robot.createScreenCapture(r);
	        } catch(Exception e) { }
	        ic.hideZoomIndicator(wasHidden);
	        if (img!=null) {
	            String title = WindowManager.getUniqueName(imp.getTitle());
	            imp2 = new ImagePlus(title, img);
	        }
	        imp2.show();
	        imp2.updateAndDraw();
	}


}

#2

Hi @Salim_Kanoun,

sorry that your post has been sitting unanswered for so long. Unfortunately, your example is by far not a minimal example illustrating your issue, so I (and possibly others as well) don’t have the time to debug this for you. But here are some thoughts:

  • Did you use the debugger of your IDE (e.g. Eclipse) to pin point where in your code the problem appears? This would certainly help to reduce the example even further and get others to reproduce the issue.
  • Did you check which of the commands you’re calling run on different threads, and which ones on the EDT? In some situations, you can create loops of commands waiting for each other’s result, which can create deadlocks and result in “frozen” behavior.
  • Overall, there are many calls to the UI in your code (cc.requestFocus(), win.toFront(), etc.) which is error prone. Is all this really necessary? What do you want to achieve?

Sorry if all this is not of much help to you. Also, if you really need to develop your own Java UI for your plugin, you might also want to consider also asking on StackOverflow.com, where more Java AWT developers can help you…


#3

Hi @imagejan

Thanks for your interest.
I recognize that my first bug report wasn’t clear enough, since i’m learning Java from scratch I was a bit lost in the GUI code.
Now that I have made some progress I can provide a much more minimal example to show my problem

As you will see, the screenShot method take a screen capture of the window.
I add a IJ.wait at the end of the capture to demonstrate the problem.
During all the wait time (5sec) the imp2.show generate a new window but the image of the capture is not printed on the screen (blank window) until the end of the 5 secs.
As well, the original is asked to resize itself but this won’t occur until the end of the 5seconds.

My problem is that I want to make such kind of automatic operation : update the stack slice, add overlay and take a screen capture.
For now I have no way to make it automatically, I have to get some “idle” state where the program stops to get the painting. So I need to ask the user to hit a button to make the capture to be sure that the painting is OK before the screen capture.

I erased the cc.requestfocus and tofront but it didn’t solve the problem.

Thanks for you help,

Salim

import java.awt.Button;
import java.awt.Image;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;

import fiji.util.gui.OverlayedImageCanvas;
import ij.IJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.ImageCanvas;
import ij.gui.ImageWindow;
import ij.gui.StackWindow;
import ij.plugin.PlugIn;

public class Vue_Shunpo implements PlugIn {

	protected HashMap<String, Button> lesBoutons;
	
	@Override
	public void run(String arg) {

		lesBoutons = new HashMap<>();
		lesBoutons.put("Capture", new Button("Capture"));
		lesBoutons.get("Capture").addActionListener(new ActionListener() {

					@Override
					public void actionPerformed(ActionEvent arg0) {
							ImagePlus imp=WindowManager.getCurrentImage();
							screenShot(imp) ;
						
					}

				});
		//add current image in customstackwindow
		if (WindowManager.getCurrentImage()==null) IJ.showMessage("Please open an ImageStack first");
		
		CustomStackWindow win = new CustomStackWindow(WindowManager.getCurrentImage());
		win.pack();
		win.setSize(530, 800);
		ImageCanvas cc=win.getCanvas();
		cc.fitToWindow();
		
	}
	
	// CustomCanvas method
	class CustomCanvas extends OverlayedImageCanvas {

		private static final long serialVersionUID = -5710708795558320699L;
		CustomCanvas(ImagePlus imp) {
			super(imp);
			}
		} 
	
	// Custum stack method modified From: https://imagej.nih.gov/ij/plugins/panel-window.html
	
	class CustomStackWindow extends StackWindow {

		private static final long serialVersionUID = -6280620624574294247L;

		CustomStackWindow(ImagePlus imp) {
			super(imp, new CustomCanvas(imp));
			addPanel();
		} // Fin constructeur CustomStackWindow

		// adding Panel GUI
		void addPanel() {
			Panel btns_glob = new Panel();
			btns_glob.add(Vue_Shunpo.this.lesBoutons.get("Capture"));
			add(btns_glob);
			pack();
		} // Fin addPanel
	}
	
	//Screenshot method taken from Screngrabber ij library
	public void screenShot(ImagePlus imp) {
	        ImageWindow win = imp.getWindow();
	        Point loc = win.getLocation();
	        ImageCanvas ic = win.getCanvas();
	        Rectangle bounds = ic.getBounds();
	        loc.x += bounds.x;
	        loc.y += bounds.y;
	        Rectangle r = new Rectangle(loc.x, loc.y, bounds.width, bounds.height);
	        Image img = null;
	        IJ.wait(250);
	        try {
	            Robot robot = new Robot();
	            img = robot.createScreenCapture(r);
	        } catch(Exception e) { }
	        ImagePlus imp2=new ImagePlus("Capture",img);
	        imp2.show();
	        imp2.updateAndDraw();
	        IJ.wait(5000);
	        imp.getWindow().setSize(300,300);
	}
}