repaintmanager.java
来自「linux下建立JAVA虚拟机的源码KAFFE」· Java 代码 · 共 784 行 · 第 1/2 页
JAVA
784 行
/** * Add a region to the set of dirty regions for a specified component. * This involves union'ing the new region with any existing dirty region * associated with the component. If the {@link #repaintWorker} class * is not active, insert it in the system event queue. * * @param component The component to add a dirty region for * @param x The left x coordinate of the new dirty region * @param y The top y coordinate of the new dirty region * @param w The width of the new dirty region * @param h The height of the new dirty region * * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty * @see #markCompletelyClean * @see #markCompletelyDirty */ public void addDirtyRegion(JComponent component, int x, int y, int w, int h) { if (w <= 0 || h <= 0 || !component.isShowing()) return; component.computeVisibleRect(rectCache); SwingUtilities.computeIntersection(x, y, w, h, rectCache); if (! rectCache.isEmpty()) { if (dirtyComponents.containsKey(component)) { SwingUtilities.computeUnion(rectCache.x, rectCache.y, rectCache.width, rectCache.height, (Rectangle) dirtyComponents.get(component)); } else { synchronized (dirtyComponents) { dirtyComponents.put(component, rectCache.getBounds()); } } if (! repaintWorker.isLive()) { repaintWorker.setLive(true); SwingUtilities.invokeLater(repaintWorker); } } } /** * Get the dirty region associated with a component, or <code>null</code> * if the component has no dirty region. * * @param component The component to get the dirty region of * * @return The dirty region of the component * * @see #dirtyComponents * @see #addDirtyRegion * @see #isCompletelyDirty * @see #markCompletelyClean * @see #markCompletelyDirty */ public Rectangle getDirtyRegion(JComponent component) { Rectangle dirty = (Rectangle) dirtyComponents.get(component); if (dirty == null) dirty = new Rectangle(); return dirty; } /** * Mark a component as dirty over its entire bounds. * * @param component The component to mark as dirty * * @see #dirtyComponents * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty * @see #markCompletelyClean */ public void markCompletelyDirty(JComponent component) { Rectangle r = component.getBounds(); addDirtyRegion(component, r.x, r.y, r.width, r.height); component.isCompletelyDirty = true; } /** * Remove all dirty regions for a specified component * * @param component The component to mark as clean * * @see #dirtyComponents * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty * @see #markCompletelyDirty */ public void markCompletelyClean(JComponent component) { synchronized (dirtyComponents) { dirtyComponents.remove(component); } component.isCompletelyDirty = false; } /** * Return <code>true</code> if the specified component is completely * contained within its dirty region, otherwise <code>false</code> * * @param component The component to check for complete dirtyness * * @return Whether the component is completely dirty * * @see #dirtyComponents * @see #addDirtyRegion * @see #getDirtyRegion * @see #isCompletelyDirty * @see #markCompletelyClean */ public boolean isCompletelyDirty(JComponent component) { if (! dirtyComponents.containsKey(component)) return false; return component.isCompletelyDirty; } /** * Validate all components which have been marked invalid in the {@link * #invalidComponents} vector. */ public void validateInvalidComponents() { // We don't use an iterator here because that would fail when there are // components invalidated during the validation of others, which happens // quite frequently. Instead we synchronize the access a little more. while (invalidComponents.size() > 0) { Component comp; synchronized (invalidComponents) { comp = (Component) invalidComponents.remove(0); } // Validate the validate component. if (! (comp.isVisible() && comp.isShowing())) continue; comp.validate(); } } /** * Repaint all regions of all components which have been marked dirty in * the {@link #dirtyComponents} table. */ public void paintDirtyRegions() { // Short cicuit if there is nothing to paint. if (dirtyComponents.size() == 0) return; synchronized (dirtyComponents) { // We sort the components by their size here. This way we have a good // chance that painting the bigger components also paints the smaller // components and we don't need to paint them twice. ArrayList repaintOrder = new ArrayList(dirtyComponents.size()); repaintOrder.addAll(dirtyComponents.keySet()); if (comparator == null) comparator = new ComponentComparator(); Collections.sort(repaintOrder, comparator); repaintUnderway = true; for (Iterator i = repaintOrder.iterator(); i.hasNext();) { JComponent comp = (JComponent) i.next(); // If a component is marked completely clean in the meantime, then skip // it. Rectangle damaged = (Rectangle) dirtyComponents.get(comp); if (damaged == null || damaged.isEmpty()) continue; comp.paintImmediately(damaged); dirtyComponents.remove(comp); } repaintUnderway = false; commitRemainingBuffers(); } } /** * Get an offscreen buffer for painting a component's image. This image * may be smaller than the proposed dimensions, depending on the value of * the {@link #doubleBufferMaximumSize} property. * * @param component The component to return an offscreen buffer for * @param proposedWidth The proposed width of the offscreen buffer * @param proposedHeight The proposed height of the offscreen buffer * * @return A shared offscreen buffer for painting */ public Image getOffscreenBuffer(Component component, int proposedWidth, int proposedHeight) { Component root = SwingUtilities.getRoot(component); Image buffer = (Image) offscreenBuffers.get(root); if (buffer == null || buffer.getWidth(null) < proposedWidth || buffer.getHeight(null) < proposedHeight) { int width = Math.max(proposedWidth, root.getWidth()); width = Math.min(doubleBufferMaximumSize.width, width); int height = Math.max(proposedHeight, root.getHeight()); height = Math.min(doubleBufferMaximumSize.height, height); buffer = component.createImage(width, height); offscreenBuffers.put(root, buffer); } return buffer; } /** * Blits the back buffer of the specified root component to the screen. If * the RepaintManager is currently working on a paint request, the commit * requests are queued up and committed at once when the paint request is * done (by {@link #commitRemainingBuffers}). This is package private because * it must get called by JComponent. * * @param root the component, either a Window or an Applet instance * @param area the area to paint on screen */ void commitBuffer(Component root, Rectangle area) { // We synchronize on dirtyComponents here because that is what // paintDirtyRegions also synchronizes on while painting. synchronized (dirtyComponents) { // If the RepaintManager is not currently painting, then directly // blit the requested buffer on the screen. if (! repaintUnderway) { Graphics g = root.getGraphics(); Image buffer = (Image) offscreenBuffers.get(root); Rectangle clip = g.getClipBounds(); if (clip != null) area = SwingUtilities.computeIntersection(clip.x, clip.y, clip.width, clip.height, area); int dx1 = area.x; int dy1 = area.y; int dx2 = area.x + area.width; int dy2 = area.y + area.height; // Make sure we have a sane clip at this point. g.clipRect(area.x, area.y, area.width, area.height); // Make sure the coordinates are inside the buffer, everything else // might lead to problems. // TODO: This code should not really be necessary, however, in fact // we have two issues here: // 1. We shouldn't get repaint requests in areas outside the buffer // region in the first place. This still happens for example // when a component is inside a JViewport, and the component has // a size that would reach beyond the window size. // 2. Graphics.drawImage() should not behave strange when trying // to draw regions outside the image. int bufferWidth = buffer.getWidth(root); int bufferHeight = buffer.getHeight(root); dx1 = Math.min(bufferWidth, dx1); dy1 = Math.min(bufferHeight, dy1); dx2 = Math.min(bufferWidth, dx2); dy2 = Math.min(bufferHeight, dy2); g.drawImage(buffer, dx1, dy1, dx2, dy2, dx1, dy1, dx2, dy2, root); g.dispose(); } // Otherwise queue this request up, until all the RepaintManager work // is done. else { if (commitRequests.containsKey(root)) SwingUtilities.computeUnion(area.x, area.y, area.width, area.height, (Rectangle) commitRequests.get(root)); else commitRequests.put(root, area); } } } /** * Commits the queued up back buffers to screen all at once. */ private void commitRemainingBuffers() { // We synchronize on dirtyComponents here because that is what // paintDirtyRegions also synchronizes on while painting. synchronized (dirtyComponents) { Set entrySet = commitRequests.entrySet(); Iterator i = entrySet.iterator(); while (i.hasNext()) { Map.Entry entry = (Map.Entry) i.next(); Component root = (Component) entry.getKey(); Rectangle area = (Rectangle) entry.getValue(); commitBuffer(root, area); i.remove(); } } } /** * Creates and returns a volatile offscreen buffer for the specified * component that can be used as a double buffer. The returned image * is a {@link VolatileImage}. Its size will be <code>(proposedWidth, * proposedHeight)</code> except when the maximum double buffer size * has been set in this RepaintManager. * * @param comp the Component for which to create a volatile buffer * @param proposedWidth the proposed width of the buffer * @param proposedHeight the proposed height of the buffer * * @since 1.4 * * @see VolatileImage */ public Image getVolatileOffscreenBuffer(Component comp, int proposedWidth, int proposedHeight) { int maxWidth = doubleBufferMaximumSize.width; int maxHeight = doubleBufferMaximumSize.height; return comp.createVolatileImage(Math.min(maxWidth, proposedWidth), Math.min(maxHeight, proposedHeight)); } /** * Get the value of the {@link #doubleBufferMaximumSize} property. * * @return The current value of the property * * @see #setDoubleBufferMaximumSize */ public Dimension getDoubleBufferMaximumSize() { return doubleBufferMaximumSize; } /** * Set the value of the {@link #doubleBufferMaximumSize} property. * * @param size The new value of the property * * @see #getDoubleBufferMaximumSize */ public void setDoubleBufferMaximumSize(Dimension size) { doubleBufferMaximumSize = size; } /** * Set the value of the {@link #doubleBufferingEnabled} property. * * @param buffer The new value of the property * * @see #isDoubleBufferingEnabled */ public void setDoubleBufferingEnabled(boolean buffer) { doubleBufferingEnabled = buffer; } /** * Get the value of the {@link #doubleBufferingEnabled} property. * * @return The current value of the property * * @see #setDoubleBufferingEnabled */ public boolean isDoubleBufferingEnabled() { return doubleBufferingEnabled; } public String toString() { return "RepaintManager"; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?