| StackWindow |

    package ij.gui;
    import java.awt.*;
    import java.awt.image.*;
    import java.awt.event.*;
    import ij.*;

    /** This class is an extended ImageWindow used to display image stacks. */
    public class StackWindow extends ImageWindow implements Runnable, AdjustmentListener, ActionListener, MouseWheelListener {

        protected Scrollbar sliceSelector;
        protected Thread thread;
        protected volatile boolean done;
        protected volatile int slice;

        public StackWindow(ImagePlus imp) {
            this(imp, null);
        }

        public StackWindow(ImagePlus imp, ImageCanvas ic) {
            super(imp, ic);
            // add slice selection slider
            ImageStack s = imp.getStack();
            int stackSize = s.getSize();
            addMouseWheelListener(this);
            sliceSelector = new Scrollbar(Scrollbar.HORIZONTAL, 1, 1, 1, stackSize+1);
            add(sliceSelector);
            ImageJ ij = IJ.getInstance();
            if (ij!=null) sliceSelector.addKeyListener(ij);
            sliceSelector.addAdjustmentListener(this);
            sliceSelector.setFocusable(false); // prevents scroll bar from blinking on Windows
            int blockIncrement = stackSize/10;
            if (blockIncrement<1) blockIncrement = 1;
            sliceSelector.setUnitIncrement(1);
            sliceSelector.setBlockIncrement(blockIncrement);
            pack();
            show();
            int previousSlice = imp.getCurrentSlice();
            imp.setSlice(1);
            if (previousSlice>1 && previousSlice<=stackSize)
                imp.setSlice(previousSlice);
            thread = new Thread(this, "SliceSelector");
            thread.start();
        }

        public synchronized void adjustmentValueChanged(AdjustmentEvent e) {
            if (!running2){
                slice = sliceSelector.getValue();
                notify();
            }
        }

        public void actionPerformed(ActionEvent e) {
        }

        public void mouseWheelMoved(MouseWheelEvent event) {
            synchronized(this) {
                int slice = imp.getCurrentSlice() + event.getWheelRotation();
                if (slice<1)
                    slice = 1;
                else if (slice>imp.getStack().getSize())
                    slice = imp.getStack().getSize();
                imp.setSlice(slice);
            }
        }

        public boolean close() {
            if (!super.close())
                return false;
            synchronized(this) {
                done = true;
                notify();
            }
            return true;
        }

        /** Displays the specified slice and updates the stack scrollbar. */
        public void showSlice(int index) {
            if (index>=1 && index<=imp.getStackSize())
                imp.setSlice(index);
        }

        /** Updates the stack scrollbar. */
        public void updateSliceSelector() {
            int stackSize = imp.getStackSize();
            int max = sliceSelector.getMaximum();
            if (max!=(stackSize+1))
                sliceSelector.setMaximum(stackSize+1);
            sliceSelector.setValue(imp.getCurrentSlice());
        }

        public void run() {
            while (!done) {
                synchronized(this) {
                    try {wait();}
                    catch(InterruptedException e) {}
                }
                if (done) return;
                if (slice>0) {
                    int s = slice;
                    slice = 0;
                    if (s!=imp.getCurrentSlice())
                        imp.setSlice(s);
                }
            }
        }

    }

| StackWindow |