📄 imgscrollpane.java
字号:
* */ public void remove(Component comp) { throw new IllegalArgumentException(); } /** * Throws an IllegalArgumentException since the components should never be * removed from this container. * */ public void removeAll() { throw new IllegalArgumentException(); } /** * Throws an IllegalArgumentException since the layout manager is * internally set and can not be changed. * */ public void setLayout(LayoutManager mgr) { throw new IllegalArgumentException(); } /** * Sets the scrollbars values, according to the image display area and * image size. The current scroll position is kept. * * */ private void setScrollbars() { Dimension asz; // actual image area size Dimension psz; // preferred size int pos; // current scroll position int szx,szy; // actual image display area size if (!imgDisplay.calcDim()) { // While the image dimensions are not known we can't really update // the scrollbar. return; } // Get the dimensions asz = imgDisplay.getSize(); psz = imgDisplay.getPreferredSize(); // Initialize lastZoom and lastSize if never done yet if (lastZoom == 0f) lastZoom = zoom; if (lastSize == null) lastSize = new Dimension(asz.width,asz.height); // Get the actual display size szx = (asz.width < psz.width) ? asz.width : psz.width; szy = (asz.height < psz.height) ? asz.height : psz.height; // Set horizontal scrollbar pos = (int)((hsbar.getValue()+lastSize.width/2f)/lastZoom*zoom-szx/2f); if (pos > (psz.width-asz.width)) pos = psz.width-asz.width; if (pos < 0) pos = 0; if (asz.width <= 0) asz.width = 1; if (psz.width <= 0) psz.width = 1; hsbar.setValues(pos,asz.width,0,psz.width); asz.width = (int)(asz.width*BLOCK_INCREMENT_PROPORTION); if (asz.width <= 0) asz.width = 1; hsbar.setBlockIncrementI(asz.width); // Set vertical scrollbar pos = (int)((vsbar.getValue()+lastSize.height/2f)/lastZoom*zoom-szy/2f); if (pos > (psz.height-asz.height)) pos = psz.height-asz.height; if (pos < 0) pos = 0; if (asz.height <= 0) asz.height = 1; if (psz.height <= 0) psz.height = 1; vsbar.setValues(pos,asz.height,0,psz.height); asz.height = (int)(asz.height*BLOCK_INCREMENT_PROPORTION); if (asz.height <= 0) asz.height = 1; vsbar.setBlockIncrementI(asz.height); // Save the zoom and display size used in the scrollbar calculation lastZoom = zoom; lastSize.width = szx; lastSize.height = szy; } /** * This class implements the component that displays the currently * viewable image portion inside the ImgScrollPane. It handles the * necessary erasing, zooming and panning. * * <P>NOTE: extending 'Canvas' instead of 'Component' solves the * flickering problem of lightweight components which are in heavyweight * containers. * * */ private class ImageScrollDisplay extends Canvas { /** The image to be displayed * * @serial */ Image img; /** The preferred size for this component * * @serial */ Dimension dim = new Dimension(); /** If the current graphics context should be erased prior to drawing * the image. Set when the image and/or zoom factor is changed. * * @serial */ boolean erase; /** The image dimensions, without any scaling. Set as soon as they are known. * * @serial */ Dimension imgDim = new Dimension(); /** The image dimension flags, as in ImageObserver. The * ImageObserver.WIDTH and ImageObserver.HEIGHT flags are set whenever * the dimension is stored in imgDim. They are reset whenever the * image changes. * * @serial */ int dimFlags; /** The last offset used in update(). * * @serial */ Point lastUpdateOffset; /** * Sets the image to display in this component. If the image is not * ready for display it will be prepared in the current thread. The * current zoom factor applies. * * <P>If the image is not ready for display (i.e. it has not been * rendered at its natural size) it will be rendered in the current * thread, if not being already rendered in another one. This means * that the current thread can block until the image is ready. * * <P>If the image is rendered incrementally (it depends on the * underlying 'ImageProducer') it will be displayed in that way if the * incremental display is set for the Component class. See the * 'imageUpdate()' method of the 'Component' class. * * <P>If the image is the same as the current one nothing is done. * * @param img The image to display. * * @see Component#imageUpdate * * */ void setImage(Image img) { // Update object state synchronized (ImgScrollPane.this) { if (img == null) { throw new IllegalArgumentException(); } // If same image do nothing if (this.img == img) { return; } // (Re)initialize dimFlags = 0; this.img = img; lastSize = null; lastZoom = 0f; setScrollbars(); // Set to erase previous image erase = true; } // Start image production (if the image is already being prepared // the method does nothing) ImgScrollPane.this.prepareImage(img,this); } /** * Returns the minimum size for this component, which is (0,0). * * @return The minimum size * * */ public Dimension getMinimumSize() { return new Dimension(0,0); } /** * Returns the maximum size for this component, which is infinite. * * @return The maximum size * * */ public Dimension getMaximumSize() { return new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE); } /** * Returns the preferred size for this component, which is the image * display size, if known, the previous image display size, if any, or * the size specified at the constructor. * * @return The preferred size for this component. * * */ public Dimension getPreferredSize() { return dim; } /** * Monitors the image rendering for dimensions and calls the * superclass' 'imageUpdate()' method. If the display size of the * image is not yet known and the image dimensions are obtained, then * the scrollbars' values are set. If 'img' is not the current image * to display nothing is done and 'false' is returned indicating that * nothing more is necessary for it. * * @see ImageObserver#imageUpdate * * @see Component#imageUpdate * * */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { if (this.img != img) { // Not the image we want to display now (might be an old one) // => do nothing and no more info needed on that image return false; } // If got the image dimensions then store them and set component // size as appropriate. if ((infoflags & (ImageObserver.WIDTH|ImageObserver.HEIGHT)) != 0) { // Got some image dimension synchronized (ImgScrollPane.this) { // Read the dimensions received if ((infoflags & ImageObserver.WIDTH) != 0) { imgDim.width = w; dimFlags |= ImageObserver.WIDTH; } if ((infoflags & ImageObserver.HEIGHT) != 0) { imgDim.height = h; dimFlags |= ImageObserver.HEIGHT; } // If we got to know the image dimensions force the layout // to be done (to see if it is necessary to show // scrollbars) if (dimFlags == (ImageObserver.WIDTH|ImageObserver.HEIGHT)) { ImgScrollPane.this.doLayout(); } } } // Call the superclass' method to continue processing return super.imageUpdate(img,infoflags,x,y,w,h); } /** * Paints the image, if any, on the graphics context by calling * update(). * * @param g The graphics context to paint on. * * */ public void paint(Graphics g) { // Now call update as usual update(g); } /** * Updates the component by drawing the relevant part of the image * that fits within the Graphics clipping area of 'g'. If the image is * not already being prepared for rendering or is not already rendered * this method does not start it. This is to avoid blocking the AWT * threads for rendering the image. The image rendering is started by * the 'setImage()' method. * * @param g The graphics context where to draw * * @see #setImage * * */ public void update(Graphics g) { Image img; // The image to display float zoom; // The zoom factor boolean erase; // If the display area should be erased int dx1,dy1; // Scaling destionation upper-left corner int dx2,dy2; // Scaling destination down-right corner int sx1,sy1; // Scaling source upper-left corner int sx2,sy2; // Scaling source down-right corner int ox,oy; // Centering offset Rectangle b; // Bounds of the display area int offx,offy; // Offset of the upper-left corner int loffx,loffy; // Offset of the upper-left corner of last update boolean copyScroll;// If the scrolling should be done by copying Rectangle clip; // The clipping area int status; // The image fetching status // Copy to local variables in a synchronized block to avoid races synchronized (ImgScrollPane.this) { img = this.img; zoom = ImgScrollPane.this.zoom; erase = this.erase; copyScroll = ImgScrollPane.this.copyScroll; this.erase = false; // If no image or the image has not started preparation yet do // nothing. We do not want to start the image preparation in // this thread because it can be long. if (img == null || (status = this.checkImage(img,null)) == 0) { return; } // Get the display size and eventual centering offset for the // image. b = this.getBounds(); ox = (b.width > dim.width) ? (b.width-dim.width)/2 : 0; oy = (b.height > dim.height) ? (b.height-dim.height)/2 : 0; // Get the display offset clip = g.getClipBounds(); if (lastUpdateOffset != null && (clip.width < b.width || clip.height < b.height)) { // The clip is smaller than the display area => we need to // paint with the last offset to avoid screwing up the // displayed image. offx = lastUpdateOffset.x; offy = lastUpdateOffset.y; } else { // The clipping area covers the whole display area => we // can use the current offset. offx = hsbar.getValue(); offy = vsbar.getValue(); } // Get and update the offset of last update if (lastUpdateOffset == null) { lastUpdateOffset = new Point(); } loffx = lastUpdateOffset.x; loffy = lastUpdateOffset.y; lastUpdateOffset.x = offx; lastUpdateOffset.y = offy; // Set the display size according to zoom if (zoom == 1f) { // Natural image size, no scaling // Displace the origin of the image according to offset ox -= offx; oy -= offy; // No zoom so no translation for scaling compensation needed sx1 = sy1 = 0; // to keep compiler happy sx2 = sy2 = 0; // to keep compiler happy dx1 = dy1 = 0; // to keep compiler happy dx2 = dy2 = 0; // to keep compiler happy } else { int sox,soy; // Scaling compensation offset // Calculate coordinates of lower right corner for scaling if (dimFlags !=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -