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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
In reply to this post by Michael Schmid
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 |
Free forum by Nabble | Edit this page |