2

ユーザーがタブをクリックしたときに実行されるフェードアニメーション付きの 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メソッドが呼び出されるため、タブは以前に選択されたタブに戻り、アニメーションを (正しく) 実行します。

したがって、タブは 2 回変更されます。1 回目はアニメーションなしでsetSelectedIndex、2 回目は で変更stateChangedされAnimatedJTabbedPaneます。

次のようなものが必要です:

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

メソッドだけでタブを変更したいstateChangedので、デフォルトのsetSelectedIndexメソッドなしでできます。どうやってやるの?

編集 私の問題の小さなグラフ:

ここに画像の説明を入力

赤い線は可視性を表します。したがって、ユーザーがタブのみstateChangedを変更すると、タブ 0がタブ 1にスムーズに変更されます。setSelectedIndex タブ 0を使用すると、すぐにタブ 1に置き換えられ、そのときだけ から目的のアニメーションが表示されるstateChangedため、ユーザーにはフラッシュが表示されます。

4

2 に答える 2

1

AncestorListener1 つの方法は、各タブのコンテンツにを追加することです。タブが可視性に追加または削除されたときに、リスナーが目的の効果をトリガーできるようにします。

画像

import java.awt.EventQueue;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

/**
 * @see http://stackoverflow.com/a/17993449/230513
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        final JTabbedPane jtp = new JTabbedPane();
        jtp.add("One", createPanel());
        jtp.add("Two", createPanel());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(jtp);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private JPanel createPanel() {
        JPanel panel = new JPanel();
        final JLabel label = new JLabel(new Date().toString());
        panel.add(label);
        panel.addAncestorListener(new AncestorListener() {
            @Override
            public void ancestorAdded(AncestorEvent event) {
                // start animation
                label.setText(new Date().toString());
            }

            @Override
            public void ancestorRemoved(AncestorEvent event) {
                // stop animation
            }

            @Override
            public void ancestorMoved(AncestorEvent event) {
            }
        });
        return panel;
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().display();
            }
        });
    }
}
于 2013-08-01T11:59:02.023 に答える