Posted by
ctrueden on
URL: http://imagej.273.s1.nabble.com/Strange-ClassCastException-A-puzzle-for-Java-ImageJ-experts-to-help-me-wit-tp3692688p3692693.html
Hi Bill,
That's a devilish problem. Normally, the message printed in the
ClassCastException is the actual (incompatible) class of the object in
question. So it would appear that your object's class is
MultiQTVirtualStack, but somehow a different MultiQTVirtualStack than the
one you are referencing in code.
The only way I know for that to happen would be if the two classes have
different packages, which would happen if you have an import statement at
the top of your class. For example, let's say there's a
foo.bar.MultiQTVirtualStack in your classpath. If your code has a line
"import foo.bar.*;" on top, you might have the problem you're seeing.
Try adding the following debugging code:
Class stackClass = stack.getClass();
Class mqtvsClass = MultiQTVirtualStack.class;
IJ.log("stack class = " + stackClass.getName());
IJ.log("MultiQTVirtualStack class = " + mqtvsClass.getName());
IJ.log("Classes equal? " + (stackClass == mqtvsClass) + "/" +
stackClass.equals(mqtvsClass));
IJ.log("path to MultiQTVirtualStack class = " +
mqtvsClass.getResource(mqtvsClass.getName() + ".class"));
IJ.log("path to stack class = " +
stackClass.getResource(stackClass.getName() + ".class"));
Let us know what you find out!
-Curtis
On Wed, Apr 29, 2009 at 9:50 AM, Bill Mohler <
[hidden email]>wrote:
> I hope that some of you with time and experience can help me with a
> suggestion. Please take some time, if you have a chance, to work through
> the details I'm providing below:
>
> I have created a new class called MultiQTVirtualStack (MQTVS for short
> here), spinning off of the success of Jeffrey Woodard's QTVirtualStack (QTVS
> for short here, which makes working with QuickTime movies in a true ImageJ
> StackWindow a delight).
>
> MQTVS extends VirtualStack (and therefore ImageStack) and allows the user
> to open a collection of QTVSs into a single Virtual HyperStack window, in
> which each QTVS plays as a separate channel, but all the QTVS-derived
> channels are navigated synchronously in the Z and T dimensions. The window
> can be viewed in either Composite (color overlay), Color (separate channel),
> or Grayscale (separate channel) modes that are available for HyperStacks.
> This all works nicely now for me. Happy to share the code, but it's not
> cleaned up pretty yet.
>
> Now I am trying to create a PluginFrame with which the user can shift the
> registration of the Z and T dimensions of the various QTVS channels of the
> MQTVS window, so as to better synchronize movies that were collected
> separately and may start at different relative times during an event of
> interest that needs to be compared.
>
> I have previously created methods MQTVS.adjustSingleMovieZ(int channel,
> boolean forward) and MQTVS.adjustSingleMovieT(int channel, boolean forward),
> which in turn call methods in my modified version of QTVS to rearrange the
> order of elements in the ArrayList, frameLocations, pointing to movie frames
> by a single position in either Z or T. This interaction of methods has
> worked well for me when I code "for" loops that make a fixed number of calls
> to the MQTVS.adjustSingleMovie...() methods from within the constructor of
> MQTVS (an experimental proof of principal that works very nicely). Here are
> the methods themselves, isolated from the rest of their classes for
> simplicity. The problems I'm having in calling these methods via a
> PluginFrame are described below.
>
> From MQTVS:
> /*These methods allow viewer to shift the Z or T positions of a given
> channel to better synchronize movies.*/
> public void adjustSingleMovieZ(int channel, boolean forward) {
> this.forward = forward;
> ((QTVirtualStack) stack[channel]).shiftMovieZ(forward);
> IJ.log("got to MQTVS.ASMZ");
>
> }
>
> public void adjustSingleMovieT(int channel, boolean forward) {
> this.forward = forward;
> ((QTVirtualStack) stack[channel]).shiftMovieT(forward);
>
> }
>
>
> From QTVS:
> /*These methods allow viewer to shift the Z or T positions of a given
> channel to better synchronize movies.*/
> public void shiftMovieT(boolean forward) {
> this.forward = forward;
> if (!forward) {
> for (int z = 0; z < maxSlicesSingleMovie ; z++) {
> this.frameLocations.add( (z*
> maxTimesSingleMovie) , this.frameLocations.get( ((z+1)* maxTimesSingleMovie)
> -1) );
> this.frameLocations.remove( ((z+1)*
> maxTimesSingleMovie) -1 );
> }
> } else {
> for (int z = maxSlicesSingleMovie-1 ; z >= 0 ; z--)
> {
> this.frameLocations.add( ((z+1)*
> maxTimesSingleMovie-1) , this.frameLocations.get( (z)* maxTimesSingleMovie
> ));
> this.frameLocations.remove( ((z)*
> maxTimesSingleMovie ) );
> }
> }
> }
>
> public void shiftMovieZ(boolean forward) {
>
> this.forward = forward;
> ArrayList copyFrames = new ArrayList();
> IJ.log("Got to the QTVS.SMZ");
>
> if (forward) {
> for (int t= 0; t < maxTimesSingleMovie; t++) {
> copyFrames.add(
> this.frameLocations.get(((maxSlicesSingleMovie-1)*maxTimesSingleMovie) ) );
>
>
> this.frameLocations.remove(((maxSlicesSingleMovie-1)*maxTimesSingleMovie)
> );
> }
> this.frameLocations.addAll(0, copyFrames);
> } else {
> for (int t= 0; t < maxTimesSingleMovie; t++) {
> copyFrames.add( this.frameLocations.get(0)
> );
> this.frameLocations.remove(0);
> }
> this.frameLocations.addAll(copyFrames);
> }
>
> }
>
>
>
> **Now to the problems I am having (apparently at the level of the JVM??).
> Here I try to call the public method MQTVS.adjustSingleMovieZ(int channel,
> boolean forward), sending parameters set by the user in the slider of the
> PluginFrame. I have no problems compiling, and get no exceptions reported
> in the log window of ImageJ. But (thanks to help from Wayne), I find a
> ClassCastException from the event dispatch thread in the console. The
> confusion comes in the apparent correctness of the type of a variable that I
> assign with the ImagePlus.getStack() command, but the wrongness of how the
> event dispatch thread deals with the variable when I try to cast it to its
> true type (I think). First I show the code from the method in the
> PluginFrame that reads the value of sliders and should call
> MQTVS.adjustSingleMovieZ(int channel, boolean forward) to change a specific
> QTVS's frame position being displayed. Then below the code, I show the
> IJ.log output from several lines in the method, and then the
> ClassCastException from the console.
>
> The key method from my PluginFrame MovieAlignFrameMOD:
> public synchronized void adjustmentValueChanged(AdjustmentEvent e) {
> ImagePlus imp = WindowManager.getCurrentImage();
>
> ImageStack stack = imp.getStack();
> IJ.log(""+stack.getClass().getName() + "1");
>
> ImageWindow win = imp.getWindow();
> int zImpPos = imp.getSlice();
> int tImpPos = imp.getFrame();
> IJ.log("beforetheloop " + imp+" \n" + imp.getStack()) ;
> boolean forward = false;
>
> if (imp==null) return;
> for (int i=0; i< imp.getNChannels(); i++){
> if (e.getSource()==sliceShifter[i]) {
> int zShiftLive = sliceShifter[i].getValue();
> int zShiftNet = zShiftLive -
> previousShiftZ[i];
> int zShiftNetAbs = zShiftNet;
> if (zShiftNet < 0) {
> zShiftNetAbs = -zShiftNet;
> forward = true;
> }
> previousShiftZ[i] = previousShiftZ[i] +
> zShiftNet;
>
> for(int j = 0; j < zShiftNetAbs; j++){
> IJ.log("intheloop j= " + j + " " +
> imp+" \n" + imp.getStack()) ;
> IJ.log(""+stack.getClass().getName() + "2");
>
> /** THIS DOES NOT REPORT, SO IT'S CLEAR THAT stack
> IS NOT reporting as instanceof MultiQTVirtualStack,
> even though it reports as one using
> stack.getClass().getName() **/
> if (stack instanceof
> MultiQTVirtualStack ) IJ.log("MultiQTVirtualStack? Yes!!!!");
>
> /*** ...But THIS STILL READS OUT AS
> MultiQTVirtualStack ******/
>
> IJ.log(""+stack.getClass().getName() + "3");
>
> /**** THIS GIVES A "SILENT" ClassCastException ON
> THE EVENT DISPATCH THREAD, CAN SEE IN CONSOLE *****/
> /* LINE 289 */ ((MultiQTVirtualStack)
> stack).adjustSingleMovieZ(i, forward);
>
> /***** Once the exception has been thrown, this next
> log statement fails to run ***********/
>
> IJ.log(""+stack.getClass().getName() + "4");
>
> }
>
> }
> else if (e.getSource()==frameShifter[i]) {
> int tShiftLive = frameShifter[i].getValue();
> int tShiftNet = tShiftLive -
> previousShiftT[i];
> previousShiftT[i] = tShiftNet;
> /****** THE ACTIONS OF THIS IF CONDITION WILL BE
> FILLED IN LATER ONCE I FIGURE OUT OTHER PROBLEMS ********/
>
> }
> notify();
> }
> }
> }
>
>
>
> Here's what is logged by the IJ.log() statements above during a slider
> adjustment:
>
> MultiQTVirtualStack1
> beforetheloop imp[3-Movie Overlay #1 : see Log window for details
> 600x411x38961]
> stack[600x411x38961]
> intheloop j= 0 imp[3-Movie Overlay #1 : see Log window for details
> 600x411x38961]
> stack[600x411x38961]
> MultiQTVirtualStack2
> MultiQTVirtualStack3
>
>
> !!Note that I did not leave out the 4th log statement in copying. The CCE
> apparently blocks the ability to run the 4th IJ.log statement after line
> 289. Also, the instanceof test fails (even before line 289), because I
> don't get the "MultiQTVirtualStack? Yes!!!" log printed.
>
>
> Finally, this is the exception from the event dispatch thread at the
> critical line 289:
>
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] Exception in
> thread "AWT-EventQueue-0" java.lang.ClassCastException: MultiQTVirtualStack
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> MovieAlignFrameMOD.adjustmentValueChanged(MovieAlignFrameMOD.java:289)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.Scrollbar.processAdjustmentEvent(Scrollbar.java:1094)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.Scrollbar.processEvent(Scrollbar.java:1061)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.Component.dispatchEventImpl(Component.java:4068)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.Component.dispatchEvent(Component.java:3903)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
> 4/28/09 10:09:08 AM [0x0-0x4c04c].gov.nih.info.rsb.ImageJ[748] at
> java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
>
>
>
> In summary, I seem to have an object called stack returned to me by
> ImagePlus.getStack() which both is a MultiQTVirtualStack by some tests and
> is NOT a MultiQTVirtualStack by others, and these other criteria are what I
> really need to make my PluginFrame work.
>
> Can anyone give me a hint of an explanation of what is going on here?
>