?? jcollapsiblepane.java
字號(hào):
setAnimationParams(new AnimationParams(30, Math.max(8,
getContentPane().getPreferredSize().height / 10), 0.01f, 1.0f));
animator.reinit(wrapper.getHeight(), getContentPane()
.getPreferredSize().height);
animateTimer.start();
}
} else {
wrapper.c.setVisible(!collapsed);
invalidate();
doLayout();
}
repaint();
firePropertyChange("collapsed", !collapsed, collapsed);
}
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
/**
* The critical part of the animation of this <code>JCollapsiblePane</code>
* relies on the calculation of its preferred size. During the animation, its
* preferred size (specially its height) will change, when expanding, from 0
* to the preferred size of the content pane, and the reverse when collapsing.
*
* @return this component preferred size
*/
public Dimension getPreferredSize() {
/*
* The preferred size is calculated based on the current position of the
* component in its animation sequence. If the Component is expanded, then
* the preferred size will be the preferred size of the top component plus
* the preferred size of the embedded content container. <p>However, if the
* scroll up is in any state of animation, the height component of the
* preferred size will be the current height of the component (as contained
* in the currentHeight variable)
*/
Dimension dim;
if (!isAnimated()) {
if (getContentPane().isVisible()) {
dim = getContentPane().getPreferredSize();
} else {
dim = super.getPreferredSize();
}
} else {
dim = new Dimension(getContentPane().getPreferredSize());
if (!getContentPane().isVisible() && currentHeight != -1) {
dim.height = currentHeight;
}
}
return dim;
}
/**
* Sets the parameters controlling the animation
*
* @param params
* @throws IllegalArgumentException
* if params is null
*/
private void setAnimationParams(AnimationParams params) {
if (params == null) { throw new IllegalArgumentException(
"params can't be null"); }
if (animateTimer != null) {
animateTimer.stop();
}
animationParams = params;
animateTimer = new Timer(animationParams.waitTime, animator);
animateTimer.setInitialDelay(0);
}
/**
* Tagging interface for containers in a JCollapsiblePane hierarchy who needs
* to be revalidated (invalidate/validate/repaint) when the pane is expanding
* or collapsing. Usually validating only the parent of the JCollapsiblePane
* is enough but there might be cases where the parent parent must be
* validated.
*/
public static interface JCollapsiblePaneContainer {
Container getValidatingContainer();
}
/**
* Parameters controlling the animations
*/
private static class AnimationParams {
final int waitTime;
final int deltaY;
final float alphaStart;
final float alphaEnd;
/**
* @param waitTime
* the amount of time in milliseconds to wait between calls to the
* animation thread
* @param deltaY
* the delta in the Y direction to inc/dec the size of the scroll
* up by
* @param alphaStart
* the starting alpha transparency level
* @param alphaEnd
* the ending alpha transparency level
*/
public AnimationParams(int waitTime, int deltaY, float alphaStart,
float alphaEnd) {
this.waitTime = waitTime;
this.deltaY = deltaY;
this.alphaStart = alphaStart;
this.alphaEnd = alphaEnd;
}
}
/**
* This class actual provides the animation support for scrolling up/down this
* component. This listener is called whenever the animateTimer fires off. It
* fires off in response to scroll up/down requests. This listener is
* responsible for modifying the size of the content container and causing it
* to be repainted.
*
* @author Richard Bair
*/
private final class AnimationListener implements ActionListener {
/**
* Mutex used to ensure that the startHeight/finalHeight are not changed
* during a repaint operation.
*/
private final Object ANIMATION_MUTEX = "Animation Synchronization Mutex";
/**
* This is the starting height when animating. If > finalHeight, then the
* animation is going to be to scroll up the component. If it is < then
* finalHeight, then the animation will scroll down the component.
*/
private int startHeight = 0;
/**
* This is the final height that the content container is going to be when
* scrolling is finished.
*/
private int finalHeight = 0;
/**
* The current alpha setting used during "animation" (fade-in/fade-out)
*/
private float animateAlpha = 1.0f;
public void actionPerformed(ActionEvent e) {
/*
* Pre-1) If startHeight == finalHeight, then we're done so stop the timer
* 1) Calculate whether we're contracting or expanding. 2) Calculate the
* delta (which is either positive or negative, depending on the results
* of (1)) 3) Calculate the alpha value 4) Resize the ContentContainer 5)
* Revalidate/Repaint the content container
*/
synchronized (ANIMATION_MUTEX) {
if (startHeight == finalHeight) {
animateTimer.stop();
animateAlpha = animationParams.alphaEnd;
// keep the content pane hidden when it is collapsed, other it may
// still receive focus.
if (finalHeight > 0) {
wrapper.showContent();
validate();
JCollapsiblePane.this.firePropertyChange(ANIMATION_STATE_KEY, null,
"expanded");
return;
}
}
final boolean contracting = startHeight > finalHeight;
final int delta_y = contracting?-1 * animationParams.deltaY
:animationParams.deltaY;
int newHeight = wrapper.getHeight() + delta_y;
if (contracting) {
if (newHeight < finalHeight) {
newHeight = finalHeight;
}
} else {
if (newHeight > finalHeight) {
newHeight = finalHeight;
}
}
animateAlpha = (float)newHeight
/ (float)wrapper.c.getPreferredSize().height;
Rectangle bounds = wrapper.getBounds();
int oldHeight = bounds.height;
bounds.height = newHeight;
wrapper.setBounds(bounds);
bounds = getBounds();
bounds.height = (bounds.height - oldHeight) + newHeight;
currentHeight = bounds.height;
setBounds(bounds);
startHeight = newHeight;
// it happens the animateAlpha goes over the alphaStart/alphaEnd range
// this code ensures it stays in bounds. This behavior is seen when
// component such as JTextComponents are used in the container.
if (contracting) {
// alphaStart > animateAlpha > alphaEnd
if (animateAlpha < animationParams.alphaEnd) {
animateAlpha = animationParams.alphaEnd;
}
if (animateAlpha > animationParams.alphaStart) {
animateAlpha = animationParams.alphaStart;
}
} else {
// alphaStart < animateAlpha < alphaEnd
if (animateAlpha > animationParams.alphaEnd) {
animateAlpha = animationParams.alphaEnd;
}
if (animateAlpha < animationParams.alphaStart) {
animateAlpha = animationParams.alphaStart;
}
}
wrapper.alpha = animateAlpha;
validate();
}
}
void validate() {
Container parent = SwingUtilities.getAncestorOfClass(
JCollapsiblePaneContainer.class, JCollapsiblePane.this);
if (parent != null) {
parent = ((JCollapsiblePaneContainer)parent).getValidatingContainer();
} else {
parent = getParent();
}
if (parent != null) {
if (parent instanceof JComponent) {
((JComponent)parent).revalidate();
} else {
parent.invalidate();
}
parent.doLayout();
parent.repaint();
}
}
/**
* Reinitializes the timer for scrolling up/down the component. This method
* is properly synchronized, so you may make this call regardless of whether
* the timer is currently executing or not.
*
* @param startHeight
* @param stopHeight
*/
public void reinit(int startHeight, int stopHeight) {
synchronized (ANIMATION_MUTEX) {
JCollapsiblePane.this.firePropertyChange(ANIMATION_STATE_KEY, null,
"reinit");
this.startHeight = startHeight;
this.finalHeight = stopHeight;
animateAlpha = animationParams.alphaStart;
currentHeight = -1;
wrapper.showImage();
}
}
}
private final class WrapperContainer extends JPanel {
private BufferedImage img;
private Container c;
float alpha = 1.0f;
public WrapperContainer(Container c) {
super(new BorderLayout());
this.c = c;
add(c, BorderLayout.CENTER);
// we must ensure the container is opaque. It is not opaque it introduces
// painting glitches specially on Linux with JDK 1.5 and GTK look and feel.
// GTK look and feel calls setOpaque(false)
if (c instanceof JComponent && !((JComponent)c).isOpaque()) {
((JComponent)c).setOpaque(true);
}
}
public void showImage() {
// render c into the img
makeImage();
c.setVisible(false);
}
public void showContent() {
currentHeight = -1;
c.setVisible(true);
}
void makeImage() {
// if we have no image or if the image has changed
if (getGraphicsConfiguration() != null && getWidth() > 0) {
Dimension dim = c.getPreferredSize();
// width and height must be > 0 to be able to create an image
if (dim.height > 0) {
img = getGraphicsConfiguration().createCompatibleImage(getWidth(),
dim.height);
c.setSize(getWidth(), dim.height);
c.paint(img.getGraphics());
} else {
img = null;
}
}
}
public void paintComponent(Graphics g) {
if (!useAnimation || c.isVisible()) {
super.paintComponent(g);
} else {
// within netbeans, it happens we arrive here and the image has not been
// created yet. We ensure it is.
if (img == null) {
makeImage();
}
// and we paint it only if it has been created and only if we have a
// valid graphics
if (g != null && img != null) {
// draw the image with y being height - imageHeight
g.drawImage(img, 0, getHeight() - img.getHeight(), null);
}
}
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
Composite oldComp = g2d.getComposite();
Composite alphaComp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
alpha);
g2d.setComposite(alphaComp);
super.paint(g2d);
g2d.setComposite(oldComp);
}
}
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -