Starting a scan using JButton will affect the display functions. How to deal with it?

Hello,

I would like to ask if anyone has experience with the following.

I have a simple script that simulates a confocal microscope scan in a “z” coordinate: The stage moves to a position, takes a picture, picture is displayed and it continues to the next position.
Everything works fine. However, when the same script is run via JButton, the script will run in order, but the image is not displayed at every step during capturing. All pictures appear at once until the end of the measurement.
That bothers me a little. As a user, I would like to see the captured image taken during each step.

Shown below - Script 1: without JButton, Script 2: with JButton.

Thank you for all the advice,
Jiri.

Script 1:
import org.micromanager.MultiStagePosition;
import org.micromanager.StagePosition;
import java.util.List;
import org.micromanager.data.Datastore;
import org.micromanager.data.Image;
import org.micromanager.data.Coords;

double nrPoints = 20; //
sleepingTime=550; //
firstPos=0; // [um]
lastPos=100; // [um]

step = (lastPos - firstPos) / ( nrPoints - 1);

distance=step;
z = mmc.getFocusDevice();

mmc.setPosition(firstPos);
mmc.sleep(sleepingTime);
zPos=(mmc.getPosition(z));
sz=zPos;

store = mm.data().createRAMDatastore();
mm.displays().createDisplay(store);

for (int i=0; i < nrPoints; i++) {

	mmc.setPosition(sz);
	mmc.sleep(sleepingTime);
	zPos=(mmc.getPosition(z));
	print(zPos);
	
	images=mm.live().snap(false);
	
	image=images.get(0);
	Coords.CoordsBuilder builder = mm.data().getCoordsBuilder();
	builder = builder.z(i);
	image = image.copyAtCoords(builder.build());
	store.putImage(image);	
	sz = zPos + distance;

}

mm.logs().showMessage(“Finished”);

Script 2:
import org.micromanager.MultiStagePosition;
import org.micromanager.StagePosition;
import java.util.List;
import org.micromanager.data.Datastore;
import org.micromanager.data.Image;
import org.micromanager.data.Coords;

button_Scan= new JButton(“Scan”);
button_Scan.setForeground(Color.black);
button_Scan.setBackground(Color.blue);

Panel_A=new JPanel(new BorderLayout());
Panel_A.setLayout(new GridLayout(1, 1 ));
Panel_A.add(button_Scan);

frame= new JFrame("");
frame.setSize(200, 100);
frame.setVisible(true);

cp = frame.getContentPane();
cp.setLayout(new GridLayout(1, 1 ));
cp.add(Panel_A);

button_Scan.addActionListener(new ActionListener() {

    actionPerformed(ActionEvent evt) { 

double nrPoints = 20; //
sleepingTime=550; //
firstPos=0; // [um]
lastPos=100; // [um]

step = (lastPos - firstPos) / ( nrPoints - 1);

distance=step;
z = mmc.getFocusDevice();

mmc.setPosition(firstPos);
mmc.sleep(sleepingTime);
zPos=(mmc.getPosition(z));
sz=zPos;

store = mm.data().createRAMDatastore();
mm.displays().createDisplay(store);

for (int i=0; i < nrPoints; i++) {

	mmc.setPosition(sz);
	mmc.sleep(sleepingTime);
	zPos=(mmc.getPosition(z));
	print(zPos);
	
	images=mm.live().snap(false);
	
	image=images.get(0);
	Coords.CoordsBuilder builder = mm.data().getCoordsBuilder();
	builder = builder.z(i);
	image = image.copyAtCoords(builder.build());
	store.putImage(image);	
	sz = zPos + distance;

};

mm.logs().showMessage(“Finished”);

	  }
  }  

);

Now I have found out that in the configuration with JButton I am able to capture 70 images in max. Then the process crashes. In a configuration without JButton, I am able to capture 500 and even more. Could it all be a memory problem? How to solve it?

I really appreciate everyone’s help.
Jiří

First, why do you want to make your own button? Did you know that you can make buttons to call scripts using Tools > Quick Access Panels?

Java interface elements run on their own thread, called EDT (Event Dispatch Thread). The JButton click runs on the EDT, as does the update of images etc… By running the whole code of your acquisition on the EDT, you block all display elements until the acquisition is done. So, you need to run the code in your ActionListener on another thread. Search the internet how to do this, for instance: Creating and Starting Java Threads.

Good luck!

1 Like

Like @nicost said, the action triggered by the button ought to be executed in a different thread. Here is a primer on that: Fiji Programming Tutorial

If it seems too complicated: create a Runnable or a Callable and submit it to an ExecutorService. The rest of the code from there will have to be continuation-style, appended at the end of the task, if needed at all.

1 Like

I tried it via JButton because I try to play, see what is and is not possible, and most importantly I learn new things.

Thank You both for Your valuable comments and advice.
Jiri

If anyone is interested, I share a script that works:

import org.micromanager.MultiStagePosition;
import org.micromanager.StagePosition;
import java.util.List;
import org.micromanager.data.Datastore;
import org.micromanager.data.Image;
import org.micromanager.data.Coords;

button_Scan= new JButton(“Scan”);
button_Scan.setForeground(Color.black);
button_Scan.setBackground(Color.blue);

Panel_A=new JPanel(new BorderLayout());
Panel_A.setLayout(new GridLayout(1, 1 ));
Panel_A.add(button_Scan);

frame= new JFrame("");
frame.setSize(200, 100);
frame.setVisible(true);

cp = frame.getContentPane();
cp.setLayout(new GridLayout(1, 1 ));
cp.add(Panel_A);

button_Scan.addActionListener(new ActionListener() {

    actionPerformed(ActionEvent evt) { 

		second.start();
    	

	  }
  }  

);

second = new Thread() {
public void run() {
try {
double nrPoints = 500; // number of points
sleepingTime=550; //
firstPos=0; // [um]
lastPos=100; // [um]

step = (lastPos - firstPos) / ( nrPoints - 1);

distance=step;
z = mmc.getFocusDevice();

mmc.setPosition(firstPos);
mmc.sleep(sleepingTime);
zPos=(mmc.getPosition(z));
sz=zPos;

store = mm.data().createRAMDatastore();
mm.displays().createDisplay(store);

for (int i=0; i < nrPoints; i++) {

	mmc.setPosition(sz);
	mmc.sleep(sleepingTime);
	zPos=(mmc.getPosition(z));
	print(zPos);
	
	images=mm.live().snap(false);
	
	image=images.get(0);
	Coords.CoordsBuilder builder = mm.data().getCoordsBuilder();
	builder = builder.z(i);
	image = image.copyAtCoords(builder.build());
	store.putImage(image);	
	sz = zPos + distance;

};

mm.logs().showMessage(“Finished”);

    } catch(InterruptedException v) {
        
        print("Problem.");
    }
}  

};

1 Like

A possible issue with your solution: since the thread is started from within the actionPerformed method, it will (I think) inherit the priority of the event dispatch thread. To ensure that’s not the case, use:

second.setPriority(Thread.NORM_PRIORITY);

… upon creating the thread.