【发布时间】:2013-08-01 11:14:26
【问题描述】:
我有带有淡入淡出动画的 JTabbedPane,这是在用户单击选项卡时执行的。为了处理动画,我重写了stateChanged 方法。
public class AnimatedJTabbedPane extends JTabbedPane implements ChangeListener, TimingTarget{
/**
*
*/
private static final long serialVersionUID = 1L;
protected BufferedImage previousTabImage;
protected BufferedImage bufferImage;
protected BufferedImage nextTabImage;
protected boolean animationStarted = false;
protected boolean paintPreviousImage = false;
protected boolean leftToRightIndex = false;
protected float fraction = 0.0f;
protected Animator animator;
protected int previousTabIndex = -1;
public AnimatedJTabbedPane(int tabPlacement) {
super(tabPlacement);
this.animator = new Animator(300, this);
this.animator.setAcceleration(0.1f);
this.animator.setDeceleration(0.8f);
this.addChangeListener(this);
}
public void stateChanged(ChangeEvent e) {
if(this.previousTabIndex != this.getSelectedIndex()){
if(this.previousTabIndex == -1){
this.previousTabIndex = this.getSelectedIndex();
}
else{
this.paintPreviousImage = true;
boolean interrupted = false;
if(this.animator.isRunning()){
this.animator.stop();
interrupted= true;
}
Component previousComponent = this.getComponentAt(this.previousTabIndex);
this.previousTabImage = this.getGraphicsConfiguration().createCompatibleImage(
previousComponent.getWidth(), previousComponent.getHeight(), Transparency.TRANSLUCENT);
previousComponent.paint(this.previousTabImage.getGraphics());
Component nextComponent = this.getComponentAt(this.getSelectedIndex());
this.nextTabImage = this.getGraphicsConfiguration().createCompatibleImage(
previousComponent.getWidth(), previousComponent.getHeight(), Transparency.TRANSLUCENT);
nextComponent.paint(this.nextTabImage.getGraphics());
if(this.previousTabIndex < this.getSelectedIndex()){
this.leftToRightIndex = true;
}
else{
this.leftToRightIndex = false;
}
this.previousTabIndex = this.getSelectedIndex();
if(interrupted){
this.animator.setStartFraction(1-this.fraction);
}
else{
this.animator.setStartFraction(0);
}
this.animationStarted = true;
this.animator.start();
}
}
}
@Override
public void paintChildren(Graphics g){
if(this.getComponentCount() != 0){
Rectangle childrenPosition = this.getComponentAt(0).getBounds();
if(this.bufferImage == null ||
this.bufferImage.getWidth() != this.getWidth() ||
this.bufferImage.getHeight() != this.getHeight()){
this.bufferImage = new BufferedImage(
this.getWidth(),
this.getHeight(),
BufferedImage.TYPE_INT_ARGB);
}
if(this.animationStarted){
if(this.paintPreviousImage){
g.drawImage(this.bufferImage, 0, 0, null);
this.paintPreviousImage = false;
}
else{
Graphics2D g2d = (Graphics2D)this.bufferImage.createGraphics();
int x = (int)childrenPosition.getX();
int y = (int)childrenPosition.getY();
this.performFadeAnimation(g2d, x, y);
g.drawImage(this.bufferImage, 0, 0, null);
g2d.dispose();
}
g.dispose();
}
else{
Graphics2D g2d = (Graphics2D)this.bufferImage.createGraphics();
super.paintChildren(g2d);
g.drawImage(this.bufferImage, 0, 0, null);
g2d.dispose();
g.dispose();
}
}
else{
super.paintChildren(g);
}
}
protected void performFadeAnimation(Graphics2D g2d, final double x, final double y){
g2d.drawImage(this.previousTabImage, (int)x, (int)y, null);
AlphaComposite composite =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, this.fraction);
g2d.setComposite(composite);
g2d.drawImage(this.nextTabImage, (int)x, (int)y, null);
}
@Override
public void begin() {
// TODO Auto-generated method stub
}
@Override
public void end() {
this.animationStarted = false;
this.repaint();
this.nextTabImage.flush();
this.nextTabImage = null;
this.previousTabImage.flush();
this.previousTabImage = null;
}
@Override
public void repeat() {
// TODO Auto-generated method stub
}
@Override
public void timingEvent(float fraction) {
this.fraction = fraction;
this.repaint();
}
}
当用户手动单击选项卡时,这非常有用。 stateChanged 事件被调用,标签随着动画的变化而变化。
我需要从代码中更改选定的选项卡,所以我使用setSelectedIndex(int) 方法。
public void setSelectedTab(int tab){
animatedTabbedPane.setSelectedIndex(tab);
}
但现在标签在setSelectedIndex 结束后立即更改 - 没有动画,然后调用 stateChanged 方法,因此标签切换回之前选择的标签并(正确)执行我的动画。
所以标签改变了两次,第一次在setSelectedIndex 之后没有动画,第二次在AnimatedJTabbedPane 中的stateChanged 之后。
我需要类似的东西:
animatedTabbedPane.firePropertyChange("stateChanged", old, new);
我只想使用stateChanged 方法更改选项卡,所以我可以不使用默认的setSelectedIndex 方法。我该怎么做?
编辑 我的问题的小图表:
红线代表可见性。因此,当用户更改选项卡时,仅调用stateChanged,tab 0 平滑地更改为 tab 1。当我使用setSelectedIndex时,tab 0 立即被 tab 1 替换,然后我才能从stateChanged 看到我想要的动画,所以用户会看到一个闪光。
【问题讨论】:
-
我能看到那个性感的动画代码吗?我的第一个猜测是 stateChanged 不是制作动画的合适位置,因为它发生在选项卡更改之后。也许您可以覆盖 JTabbedPane.setSelectedIndex(int i) 并将动画代码放在超级调用之前,或者直接调用 model.setSelectedIndex(i) 。如果不是这样,您将不得不拦截和处理事件。
-
我添加了我的 AnimatedTabbedPane 的完整代码。我在互联网上的某个地方找到了这个,但我现在找不到来源。
-
Animator 来自哪个包/项目?
-
是
timingframeworklink -
不错的图片,只是看不出与问题有多大关系 :-) 无论如何,它对我来说很好,所以获得更多帮助的方法是...... SSCCE
标签: java swing events jtabbedpane