Variables keep persisting even on plugin restart.

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Variables keep persisting even on plugin restart.

MrScientistman2
HI. Im making a plugin with a menu in swing, that has tons of variables, many
static and final. However, when
a user has loaded a wrong image type etc, I ask the user to restart the
plugin. To my great frustration, I realize that the second time the plugin
is started (from the menu) many variables still alive in the first plugin
instance and being used in the second instance, leading to many bugs. How
can I properly close a plugin and make sure all variables are no longer
active. Here is a minimal plugin demonstrating the problem. In the first
plugin instance IJ.log(size) prints 3, but in the second it prints 6! It
should print 3 in both cases.

package com.mycompany.imagej;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import ij.IJ;
import ij.ImageJ;
import ij.plugin.PlugIn;

public class Image_Rearranger implements PlugIn {
        public static DefaultListModel<String> List_Colors = new
DefaultListModel<String>();
        JFrame Frame_MainMenu;
       
        public void run(String arg) {
                List_Colors.addElement("White");
                List_Colors.addElement("Yellow");
                List_Colors.addElement("Cyan");
               
                String size = Integer.toString(List_Colors.size());
                IJ.log(size); //First run = 3. Second run = 6!!!
               
                Frame_MainMenu = new JFrame("debug");
                Frame_MainMenu.setBounds(0, 0, 275, 350);
                Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                Frame_MainMenu.show();
        }
}





--
Sent from: http://imagej.1557.x6.nabble.com/

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Peterbauer Thomas

On 22.01.19 23:13, MrScientistman2 wrote:

> HI. Im making a plugin with a menu in swing, that has tons of variables, many
> static and final. However, when
> a user has loaded a wrong image type etc, I ask the user to restart the
> plugin. To my great frustration, I realize that the second time the plugin
> is started (from the menu) many variables still alive in the first plugin
> instance and being used in the second instance, leading to many bugs. How
> can I properly close a plugin and make sure all variables are no longer
> active. Here is a minimal plugin demonstrating the problem. In the first
> plugin instance IJ.log(size) prints 3, but in the second it prints 6! It
> should print 3 in both cases.
>
> package com.mycompany.imagej;
>
> import javax.swing.DefaultListModel;
> import javax.swing.JFrame;
> import javax.swing.WindowConstants;
> import ij.IJ;
> import ij.ImageJ;
> import ij.plugin.PlugIn;
>
> public class Image_Rearranger implements PlugIn {
> public static DefaultListModel<String> List_Colors = new
> DefaultListModel<String>();
> JFrame Frame_MainMenu;
>
> public void run(String arg) {
> List_Colors.addElement("White");
> List_Colors.addElement("Yellow");
> List_Colors.addElement("Cyan");
>
> String size = Integer.toString(List_Colors.size());
> IJ.log(size); //First run = 3. Second run = 6!!!
>
> Frame_MainMenu = new JFrame("debug");
> Frame_MainMenu.setBounds(0, 0, 275, 350);
> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
> Frame_MainMenu.show();
> }
> }

Don't use static variables. They are bound to the entire class, not to a
particular instance of a class. In your example, the first plugin
instance adds 3 elements to the static DefaultListModel. If you close
the first instance, the class still holds a model with 3 elements. If
you open the second instance, this one adds another 3 elements, yielding
a model with 6 entries, and so on. Static members must be only used for
things which you really want to keep independent of a particular instance.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

MrScientistman2
Thanks Peterbauer Thomas. However, is there any other way to fix this?
Something that would simulate restarting ImageJ maybe? Because I believe I
need to use static variables in my plugin in many cases.

Does it matter where I declare the static variable? If it is in the class
scope, or the run method scope for example?



--
Sent from: http://imagej.1557.x6.nabble.com/

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Peterbauer Thomas

On 22.01.19 23:43, MrScientistman2 wrote:
> However, is there any other way to fix this?
> Something that would simulate restarting ImageJ maybe? Because I believe I
> need to use static variables in my plugin in many cases.
>
> Does it matter where I declare the static variable? If it is in the class
> scope, or the run method scope for example?

Declare it in the class scope as you did, just without "static". For
each plugin called, ImageJ constructs an object (using the default
paramterless constructor), which hold an empty DefaultListModel. Upon
being called with the run(String) method, you fill the model with your
colors. Once this particular instance is closed/destroyed, the object is
gone, as is the DefaultListModel with its content. If your plugin is
called again (either while another instance is running or not), it is
also initialized with an empty model.

import ij.IJ;
import ij.plugin.PlugIn;
import javax.swing.DefaultListModel;

public class Image_Rearranger implements PlugIn {

    DefaultListModel<String> listModel = new DefaultListModel<String>();

    @Override
    public void run(String arg) {
       listModel.addElement("White");
       listModel.addElement("Yellow");
       listModel.addElement("Cyan");
       IJ.log(String.valueOf(listModel.size()));
    }
}

BTW, I note that your plugin constructs its own JFrame. ImageJ, however,
provides a template for plugins with a GUI window. Let your class extend
ij.plugin.frame.PlugInFrame and implement a constructor (where you can
do all the stuff like creating list models and filling them):

import ij.plugin.frame.PlugInFrame;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;

public class Image_Rearranger extends PlugInFrame {

    DefaultListModel<String> listModel;

    public Image_Rearranger() {
       super("Image Rearranger");
       this.listModel = new DefaultListModel<>();
       listModel.addElement("White");
       listModel.addElement("Yellow");
       listModel.addElement("Cyan");
       setSize(400, 400);
       add(new JLabel("My very own DefaultListModel has
"+String.valueOf(listModel.size()+" elements")));
       setLocationRelativeTo(null);
       show();
    }
}


--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

MrScientistman2
Thanks. I added List_Colors.removeAllElements(); so it clears on every
initialization. I have no other static variables in my main code-file now
(Image_Rearranger.java). However, Im still facing difficulties. To make it
clearer, I've uploaded the code and compiled jar to github:

https://github.com/Anders-Lunde/Image_Rearranger

The problem: I declare "JFrame Frame_MainMenu;" in the class scope. No
static. The plugin asks the user to open an image. Frame_MainMenu is then
displayed. However, how is the user supposed to restart the plugin, with all
references to the previous instance abolished? I have tried the following
options for when the user clicks the "X" button in the Frame_MainMenu:

Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Frame_MainMenu.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

EXIT_ON_CLOSE closes ImageJ, which is not what I want. DISPOSE_ON_CLOSE
closes Frame_MainMenu but the plugin appears to still run in the background,
and interferes with new instances of the plugin. I say this because when
closing the Frame_MainMenu, and starting a new instance through the
"Plugin->Image Rearranger" menu in ImageJ, terrible bugs happen: When the
user finishes a round of the "Add Element"-button wizard,
Frame_MainMenu.show() is called, but what happens then is that
Frame_MainMenu from BOTH the old and the new plugin is shown, and runtime
errors occur. So obviously the old/first instance of the plugin is still
alive causing troubles.

Is there no simple way to add a button or something that completely
abolishes all memory of the plugin instance when clicked? So that when the
plugin is opened again from the menu it behaves as if it was ran the first
time on a newly started ImageJ instance?

P.S.
My plugin has been made by various freelancer programmers, since Im no pro
myself. The "Add Element-button wizard for example was made by someone else.
There are several static variables there; I think because it needs to
communicate with the main code in Image_Rearranger.java. Maybe those are a
root of my trouble as well?



--
Sent from: http://imagej.1557.x6.nabble.com/

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Peterbauer Thomas

On 23.01.19 20:39, MrScientistman2 wrote:

> Thanks. I added List_Colors.removeAllElements(); so it clears on every
> initialization. I have no other static variables in my main code-file now
> (Image_Rearranger.java). However, Im still facing difficulties. To make it
> clearer, I've uploaded the code and compiled jar to github:
>
> https://github.com/Anders-Lunde/Image_Rearranger
>
> The problem: I declare "JFrame Frame_MainMenu;" in the class scope. No
> static. The plugin asks the user to open an image. Frame_MainMenu is then
> displayed. However, how is the user supposed to restart the plugin, with all
> references to the previous instance abolished? I have tried the following
> options for when the user clicks the "X" button in the Frame_MainMenu:
>
> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
>
> EXIT_ON_CLOSE closes ImageJ, which is not what I want. DISPOSE_ON_CLOSE
> closes Frame_MainMenu but the plugin appears to still run in the background,
> and interferes with new instances of the plugin. I say this because when
> closing the Frame_MainMenu, and starting a new instance through the
> "Plugin->Image Rearranger" menu in ImageJ, terrible bugs happen: When the
> user finishes a round of the "Add Element"-button wizard,
> Frame_MainMenu.show() is called, but what happens then is that
> Frame_MainMenu from BOTH the old and the new plugin is shown, and runtime
> errors occur. So obviously the old/first instance of the plugin is still
> alive causing troubles.
>
> Is there no simple way to add a button or something that completely
> abolishes all memory of the plugin instance when clicked? So that when the
> plugin is opened again from the menu it behaves as if it was ran the first
> time on a newly started ImageJ instance?
>
> P.S.
> My plugin has been made by various freelancer programmers, since Im no pro
> myself. The "Add Element-button wizard for example was made by someone else.
> There are several static variables there; I think because it needs to
> communicate with the main code in Image_Rearranger.java. Maybe those are a
> root of my trouble as well?

Sorry, but I fear this project has grown too big for a quick fix.
There's no way to "abolish" static variables in a running Java machine
except exiting it (i.e., quitting ImageJ, in your case). They live with
the class, regardless whether there is an instance of that class around
or not. You would have to attach a WindowListener (or WindowAdapter, as
shown in one of my previous answers) to your frame, which listens for
the closing event (when the user clicks the "X" button on the frame),
and then resets each and every static variable to its initial/desired
value. It seems that your "freelancers" were not familiar with the
principles of object oriented programming. To make things accessible to
other parts of a program, one passes non-static references of instances,
either to constructors or by using getter and setter methods. These
instance variables are garbage collected whenever no other object holds
a reference of them, and so closing a frame which holds lists, buttons,
wizards or whatever else works with them as you expect it.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Michael Schmid-3
Hi Thomas,

you don't want us to debug a code with 4000+ lines in the main class,
and many other classes, do you?

Anyhow, you could try your main frame implementing WindowListener, and
cleaning up whatever you want to clean up in windowClosing(WindowEvent e).

I don't know what the Wizard class should do; at least it is strange to
have static variables there. This means that all instances of Wizard
would use the same values.
You could try deleting the "static" for all variables there.

What static variables are good for:
- Remembering previous values as defaults, e.g. the directory where to
open files in the ImageJ file open dialog.
- Preferences that should be kept over a session.
- Making sure that there is only a single instance of some object e.g.
when the ImageJ Brightness&Contrast panel is already open, trying to
open it again will not open another such panel, but bring the existing
one to the front. Here, a static variable "instance" refers the dialog
that is currently open.
- Constants (static final variable)

I see no point in using static variables for communication between classes.

Michael
________________________________________________________________
On 24.01.19 00:57, Peterbauer Thomas wrote:

>
> On 23.01.19 20:39, MrScientistman2 wrote:
>> Thanks. I added List_Colors.removeAllElements(); so it clears on every
>> initialization. I have no other static variables in my main code-file now
>> (Image_Rearranger.java). However, Im still facing difficulties. To make it
>> clearer, I've uploaded the code and compiled jar to github:
>>
>> https://github.com/Anders-Lunde/Image_Rearranger
>>
>> The problem: I declare "JFrame Frame_MainMenu;" in the class scope. No
>> static. The plugin asks the user to open an image. Frame_MainMenu is then
>> displayed. However, how is the user supposed to restart the plugin, with all
>> references to the previous instance abolished? I have tried the following
>> options for when the user clicks the "X" button in the Frame_MainMenu:
>>
>> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
>> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
>>
>> EXIT_ON_CLOSE closes ImageJ, which is not what I want. DISPOSE_ON_CLOSE
>> closes Frame_MainMenu but the plugin appears to still run in the background,
>> and interferes with new instances of the plugin. I say this because when
>> closing the Frame_MainMenu, and starting a new instance through the
>> "Plugin->Image Rearranger" menu in ImageJ, terrible bugs happen: When the
>> user finishes a round of the "Add Element"-button wizard,
>> Frame_MainMenu.show() is called, but what happens then is that
>> Frame_MainMenu from BOTH the old and the new plugin is shown, and runtime
>> errors occur. So obviously the old/first instance of the plugin is still
>> alive causing troubles.
>>
>> Is there no simple way to add a button or something that completely
>> abolishes all memory of the plugin instance when clicked? So that when the
>> plugin is opened again from the menu it behaves as if it was ran the first
>> time on a newly started ImageJ instance?
>>
>> P.S.
>> My plugin has been made by various freelancer programmers, since Im no pro
>> myself. The "Add Element-button wizard for example was made by someone else.
>> There are several static variables there; I think because it needs to
>> communicate with the main code in Image_Rearranger.java. Maybe those are a
>> root of my trouble as well?
>
> Sorry, but I fear this project has grown too big for a quick fix.
> There's no way to "abolish" static variables in a running Java machine
> except exiting it (i.e., quitting ImageJ, in your case). They live with
> the class, regardless whether there is an instance of that class around
> or not. You would have to attach a WindowListener (or WindowAdapter, as
> shown in one of my previous answers) to your frame, which listens for
> the closing event (when the user clicks the "X" button on the frame),
> and then resets each and every static variable to its initial/desired
> value. It seems that your "freelancers" were not familiar with the
> principles of object oriented programming. To make things accessible to
> other parts of a program, one passes non-static references of instances,
> either to constructors or by using getter and setter methods. These
> instance variables are garbage collected whenever no other object holds
> a reference of them, and so closing a frame which holds lists, buttons,
> wizards or whatever else works with them as you expect it.
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Peterbauer Thomas

On 2019-01-24 10:42, Michael Schmid wrote:
> Hi Thomas,
>
> you don't want us to debug a code with 4000+ lines in the main class,
> and many other classes, do you?


No, I don't. You are confusing questions and answers. The code is from
MrScientistman2, not mine. I just added a similar comment on static
variables as you did. It starts after a quote from MrScientistman2.

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html
Reply | Threaded
Open this post in threaded view
|

Re: Variables keep persisting even on plugin restart.

Michael Schmid-3
In reply to this post by Michael Schmid-3
Ooops, my apologies!

I should have written "Hi Anders".
Of course, the reply was meant for Anders (MrScientistman2), who has the
problematic code, not to Thomas, who replied with suggestions how to fix
the problem.

Sorry, I had missed these suggestions because they were below the bottom
of the screen.


Michael
________________________________________________________________
On 24.01.19 10:42, Michael Schmid wrote:

> Hi Thomas,
>
> you don't want us to debug a code with 4000+ lines in the main class,
> and many other classes, do you?
>
> Anyhow, you could try your main frame implementing WindowListener, and
> cleaning up whatever you want to clean up in windowClosing(WindowEvent e).
>
> I don't know what the Wizard class should do; at least it is strange to
> have static variables there. This means that all instances of Wizard
> would use the same values.
> You could try deleting the "static" for all variables there.
>
> What static variables are good for:
> - Remembering previous values as defaults, e.g. the directory where to
> open files in the ImageJ file open dialog.
> - Preferences that should be kept over a session.
> - Making sure that there is only a single instance of some object e.g.
> when the ImageJ Brightness&Contrast panel is already open, trying to
> open it again will not open another such panel, but bring the existing
> one to the front. Here, a static variable "instance" refers the dialog
> that is currently open.
> - Constants (static final variable)
>
> I see no point in using static variables for communication between classes.
>
> Michael
> ________________________________________________________________
> On 24.01.19 00:57, Peterbauer Thomas wrote:
>>
>> On 23.01.19 20:39, MrScientistman2 wrote:
>>> Thanks. I added List_Colors.removeAllElements(); so it clears on every
>>> initialization. I have no other static variables in my main code-file
>>> now
>>> (Image_Rearranger.java). However, Im still facing difficulties. To
>>> make it
>>> clearer, I've uploaded the code and compiled jar to github:
>>>
>>> https://github.com/Anders-Lunde/Image_Rearranger
>>>
>>> The problem: I declare "JFrame Frame_MainMenu;" in the class scope. No
>>> static. The plugin asks the user to open an image. Frame_MainMenu is
>>> then
>>> displayed. However, how is the user supposed to restart the plugin,
>>> with all
>>> references to the previous instance abolished? I have tried the
>>> following
>>> options for when the user clicks the "X" button in the Frame_MainMenu:
>>>
>>> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
>>>
>>> Frame_MainMenu.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
>>>
>>> EXIT_ON_CLOSE closes ImageJ, which is not what I want. DISPOSE_ON_CLOSE
>>> closes Frame_MainMenu but the plugin appears to still run in the
>>> background,
>>> and interferes with new instances of the plugin. I say this because when
>>> closing the Frame_MainMenu, and starting a new instance through the
>>> "Plugin->Image Rearranger" menu in ImageJ, terrible bugs happen: When
>>> the
>>> user finishes a round of the "Add Element"-button wizard,
>>> Frame_MainMenu.show() is called, but what happens then is that
>>> Frame_MainMenu from BOTH the old and the new plugin is shown, and
>>> runtime
>>> errors occur. So obviously the old/first instance of the plugin is still
>>> alive causing troubles.
>>>
>>> Is there no simple way to add a button or something that completely
>>> abolishes all memory of the plugin instance when clicked? So that
>>> when the
>>> plugin is opened again from the menu it behaves as if it was ran the
>>> first
>>> time on a newly started ImageJ instance?
>>>
>>> P.S.
>>> My plugin has been made by various freelancer programmers, since Im
>>> no pro
>>> myself. The "Add Element-button wizard for example was made by
>>> someone else.
>>> There are several static variables there; I think because it needs to
>>> communicate with the main code in Image_Rearranger.java. Maybe those
>>> are a
>>> root of my trouble as well?
>>
>> Sorry, but I fear this project has grown too big for a quick fix.
>> There's no way to "abolish" static variables in a running Java machine
>> except exiting it (i.e., quitting ImageJ, in your case). They live with
>> the class, regardless whether there is an instance of that class around
>> or not. You would have to attach a WindowListener (or WindowAdapter, as
>> shown in one of my previous answers) to your frame, which listens for
>> the closing event (when the user clicks the "X" button on the frame),
>> and then resets each and every static variable to its initial/desired
>> value. It seems that your "freelancers" were not familiar with the
>> principles of object oriented programming. To make things accessible to
>> other parts of a program, one passes non-static references of instances,
>> either to constructors or by using getter and setter methods. These
>> instance variables are garbage collected whenever no other object holds
>> a reference of them, and so closing a frame which holds lists, buttons,
>> wizards or whatever else works with them as you expect it.
>>
>> --
>> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html