Evento fire stateChanged no JTabbedPane
Eu tenho JTabbedPane com animação de desvanecimento, que é realizada quando o usuário clica em guias. Para lidar com a animação, anulostateChanged
método.
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();
}
}
Isso funciona muito bem quando o usuário clica nas guias manualmente.stateChanged
evento é chamado e as guias estão mudando com a animação.
Preciso alterar a guia selecionada do código, então estou usandosetSelectedIndex(int)
método.
public void setSelectedTab(int tab){
animatedTabbedPane.setSelectedIndex(tab);
}
Mas agora a aba é alterada instantaneamente depoissetSelectedIndex
termina - sem animação, e depoisstateChanged
O método é chamado, portanto, a guia volta para a guia anterior selecionada e executa (corretamente) a minha animação.
Então tab está mudando duas vezes, primeiro sem animação depoissetSelectedIndex
e segunda vez depoisstateChanged
emAnimatedJTabbedPane
.
Eu preciso de algo como:
animatedTabbedPane.firePropertyChange("stateChanged", old, new);
Quero alterar as guias apenas comstateChanged
método, então eu posso fazer sem padrãosetSelectedIndex
método. Como eu posso fazer isso?
EDITAR Um pequeno gráfico do meu problema:
A linha vermelha representa visibilidade. Então, quando o usuário muda apenas a guiastateChanged
é chamado,guia 0 suavemente muda paraguia 1. Quando eu usosetSelectedIndex
guia 0 é imediatamente substituído porguia 1 e só então eu posso ver minha animação desejadastateChanged
, então os usuários vêem um flash.