本文介绍了Fire State在JTabbedPane上更改事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有JTabbedPane的褪色动画,当用户点击标签时执行。要处理动画,我将覆盖 stateChanged 方法。

  public class AnimatedJTabbedPane extends JTabbedPane实现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 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 interrup = false;
if(this.animator.isRunning()){
this.animator.stop();
interrup = true;
}

组件previousComponent = this.getComponentAt(this.previousTabIndex);

this.previousTabImage = this.getGraphicsConfiguration()。createCompatibleImage(
previousComponent.getWidth(),previousComponent.getHeight(),Transparency.TRANSLUCENT);

previousComponent.paint(this.previousTabImage.getGraphics());

组件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();
如果(中断){
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自动生成的方法存根
}

@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自动生成的方法存根
}

@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 之后没有动画,第二次在 stateChanged AnimatedJTabbedPane



我需要这样的东西:

  animatedTabbedPane.firePropertyChange(stateChanged,old,new); 

我只想使用 stateChanged 方法,所以我可以做没有默认的 setSelectedIndex 方法。如何做到这一点?



编辑
我的问题的一个小图:





红线代表可见度。所以当用户更改标签只有 stateChanged 被调用时,标签0 顺利地更改为标签1 。当我使用 setSelectedIndex 标签0 立即被替换为标签1 ,只有这样我才能看到我想要的动画从 stateChanged ,所以用户看到一个闪光。

解决方案

我的问题的原因。



这是线程问题,而不是动画本身。我在 EDT 之外打电话 setSelectedIndex ,所以我的JTabbedPane立即更新,然后执行了 EDT 的动画。



anserw是:

  public void setSelectedTab(final int tab )throws InterruptedException,InvocationTargetException {
if(!SwingUtilities.isEventDispatchThread()){
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run(){
animatedTabbedPane.setSelectedIndex(tab);
}
});
}
else
animatedTabbedPane.setSelectedIndex(tab);
}

更改 EDT 中的标签不会不需要闪现了。


I have JTabbedPane with fade animation, which is performed when user clicks tabs. To handle animation I override stateChanged method.

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();
}

}

This works great when user clicks tabs manually. stateChanged event is called and tabs are changing with animation.

I need to change selected tab from code, so I'm using setSelectedIndex(int) method.

public void setSelectedTab(int tab){
    animatedTabbedPane.setSelectedIndex(tab);
}

But right now tab is changed instantly after setSelectedIndex ends - without animation, and then stateChanged method is called, so tab switch back to previously tab selected and perform (correctly) my animation.

So tab is changing twice, first without animation after setSelectedIndex and second time after stateChanged in AnimatedJTabbedPane.

I need something like:

 animatedTabbedPane.firePropertyChange("stateChanged", old, new);

I want to change tabs only with stateChanged method, so I can do without default setSelectedIndex method. How can I do that?

EDITA little graph of my problem:

The red line represents visibility. So when user changes tab only stateChanged is called, tab 0 smoothly changes to tab 1. When I use setSelectedIndex tab 0 is immediately replaced with tab 1 and only then I can see my desired animation from stateChanged, so the users see a flash.

解决方案

I found the real reason of my problem.

It was the thread problem, not the animation itself. I was calling setSelectedIndex outside EDT so my JTabbedPane was updated instantly and then the animation from EDT was performed.

The anserw is:

public void setSelectedTab(final int tab) throws InterruptedException, InvocationTargetException{
    if(!SwingUtilities.isEventDispatchThread()){
        SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
                animatedTabbedPane.setSelectedIndex(tab);
            }
        });
    }
    else
        animatedTabbedPane.setSelectedIndex(tab);
}

Changing tabs inside EDT doesn't couse unwanted flash anymore.

这篇关于Fire State在JTabbedPane上更改事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-31 23:58