📄 jcollapsiblepane.java
字号:
/**
* $ $ License.
*
* Copyright $ L2FProd.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.l2fprod.common.swing;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
* <code>JCollapsiblePane</code> provides a component which can collapse or
* expand its content area with animation and fade in/fade out effects.
* It also acts as a standard container for other Swing components.
*
* <p>
* In this example, the <code>JCollapsiblePane</code> is used to build
* a Search pane which can be shown and hidden on demand.
*
* <pre>
* <code>
* JCollapsiblePane cp = new JCollapsiblePane();
*
* // JCollapsiblePane can be used like any other container
* cp.setLayout(new BorderLayout());
*
* // the Controls panel with a textfield to filter the tree
* JPanel controls = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 0));
* controls.add(new JLabel("Search:"));
* controls.add(new JTextField(10));
* controls.add(new JButton("Refresh"));
* controls.setBorder(new TitledBorder("Filters"));
* cp.add("Center", controls);
*
* JFrame frame = new JFrame();
* frame.setLayout(new BorderLayout());
*
* // Put the "Controls" first
* frame.add("North", cp);
*
* // Then the tree - we assume the Controls would somehow filter the tree
* JScrollPane scroll = new JScrollPane(new JTree());
* frame.add("Center", scroll);
*
* // Show/hide the "Controls"
* JButton toggle = new JButton(cp.getActionMap().get("toggle"));
* frame.add("South", toggle);
*
* frame.pack();
* frame.setVisible(true);
* </code>
* </pre>
*
* <p>
* Note: <code>JCollapsiblePane</code> requires its parent container to have a
* {@link java.awt.LayoutManager} using {@link #getPreferredSize()} when
* calculating its layout (example {@link com.l2fprod.common.swing.PercentLayout},
* {@link java.awt.BorderLayout}).
*
* @javabean.attribute
* name="isContainer"
* value="Boolean.TRUE"
* rtexpr="true"
*
* @javabean.attribute
* name="containerDelegate"
* value="getContentPane"
*
* @javabean.class
* name="JCollapsiblePane"
* shortDescription="A pane which hides its content with an animation."
* stopClass="java.awt.Component"
*
* @author rbair (from the JDNC project)
* @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a>
*/
public class JCollapsiblePane extends JPanel {
/**
* Used when generating PropertyChangeEvents for the "animationState" property
*/
public final static String ANIMATION_STATE_KEY = "animationState";
/**
* Indicates whether the component is collapsed or expanded
*/
private boolean collapsed = false;
/**
* Timer used for doing the transparency animation (fade-in)
*/
private Timer animateTimer;
private AnimationListener animator;
private int currentHeight = -1;
private WrapperContainer wrapper;
private boolean useAnimation = true;
private AnimationParams animationParams;
/**
* Constructs a new JCollapsiblePane with a {@link JPanel} as content pane and
* a vertical {@link PercentLayout} with a gap of 2 pixels as layout manager.
*/
public JCollapsiblePane() {
super.setLayout(new BorderLayout(0, 0));
JPanel panel = new JPanel();
panel.setLayout(new PercentLayout(PercentLayout.VERTICAL, 2));
setContentPane(panel);
animator = new AnimationListener();
setAnimationParams(new AnimationParams(30, 8, 0.01f, 1.0f));
// add an action to automatically toggle the state of the pane
getActionMap().put("toggle", new AbstractAction("Toggle") {
public void actionPerformed(ActionEvent e) {
setCollapsed(!isCollapsed());
}
});
}
/**
* Sets the content pane of this JCollapsiblePane. Components must be added
* to this content pane, not to the JCollapsiblePane.
*
* @param contentPanel
* @throws IllegalArgumentException
* if contentPanel is null
*/
public void setContentPane(Container contentPanel) {
if (contentPanel == null) {
throw new IllegalArgumentException("Content pane can't be null");
}
if (wrapper != null) {
super.remove(wrapper);
}
wrapper = new WrapperContainer(contentPanel);
super.addImpl(wrapper, BorderLayout.CENTER, -1);
}
/**
* @return the content pane
*/
public Container getContentPane() {
return wrapper.c;
}
/**
* Overriden to redirect call to the content pane.
*/
public void setLayout(LayoutManager mgr) {
// wrapper can be null when setLayout is called by "super()" constructor
if (wrapper != null) {
getContentPane().setLayout(mgr);
}
}
/**
* Overriden to redirect call to the content pane.
*/
protected void addImpl(Component comp, Object constraints, int index) {
getContentPane().add(comp, constraints, index);
}
/**
* Overriden to redirect call to the content pane
*/
public void remove(Component comp) {
getContentPane().remove(comp);
}
/**
* Overriden to redirect call to the content pane.
*/
public void remove(int index) {
getContentPane().remove(index);
}
/**
* Overriden to redirect call to the content pane.
*/
public void removeAll() {
getContentPane().removeAll();
}
/**
* If true, enables the animation when pane is collapsed/expanded. If false,
* animation is turned off.
*
* <p>
* When animated, the <code>JCollapsiblePane</code> will progressively
* reduce (when collapsing) or enlarge (when expanding) the height of its
* content area until it becomes 0 or until it reaches the preferred height of
* the components it contains. The transparency of the content area will also
* change during the animation.
*
* <p>
* If not animated, the <code>JCollapsiblePane</code> will simply hide
* (collapsing) or show (expanding) its content area.
*
* @param animated
* @javabean.property bound="true" preferred="true"
*/
public void setAnimated(boolean animated) {
if (animated != useAnimation) {
useAnimation = animated;
firePropertyChange("animated", !useAnimation, useAnimation);
}
}
/**
* @return true if the pane is animated, false otherwise
* @see #setAnimated(boolean)
*/
public boolean isAnimated() {
return useAnimation;
}
/**
* @return true if the pane is collapsed, false if expanded
*/
public boolean isCollapsed() {
return collapsed;
}
/**
* Expands or collapses this <code>JCollapsiblePane</code>.
*
* <p>
* If the component is collapsed and <code>val</code> is false, then this
* call expands the JCollapsiblePane, such that the entire JCollapsiblePane
* will be visible. If {@link #isAnimated()} returns true, the expansion will
* be accompanied by an animation.
*
* <p>
* However, if the component is expanded and <code>val</code> is true, then
* this call collapses the JCollapsiblePane, such that the entire
* JCollapsiblePane will be invisible. If {@link #isAnimated()} returns true,
* the collapse will be accompanied by an animation.
*
* @see #isAnimated()
* @see #setAnimated(boolean)
* @javabean.property
* bound="true"
* preferred="true"
*/
public void setCollapsed(boolean val) {
if (collapsed != val) {
collapsed = val;
if (isAnimated()) {
if (collapsed) {
setAnimationParams(new AnimationParams(30, Math.max(8, wrapper
.getHeight() / 10), 1.0f, 0.01f));
animator.reinit(wrapper.getHeight(), 0);
animateTimer.start();
} else {
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.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -