Fire stateChanged-Ereignis in JTabbedPane
Ich habe JTabbedPane mit Fade-Animation, die ausgeführt wird, wenn der Benutzer auf Registerkarten klickt. Um mit der Animation umzugehen, überschreibe ichstateChanged
Methode.
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();
}
}
Dies funktioniert hervorragend, wenn der Benutzer manuell auf Registerkarten klickt.stateChanged
Das Ereignis wird aufgerufen und die Registerkarten ändern sich mit der Animation.
Ich muss die ausgewählte Registerkarte im Code ändern, also verwende ichsetSelectedIndex(int)
Methode.
public void setSelectedTab(int tab){
animatedTabbedPane.setSelectedIndex(tab);
}
Aber im Moment wird die Registerkarte sofort danach geändertsetSelectedIndex
endet - ohne Animation und dannstateChanged
Die Methode wird aufgerufen. Wechseln Sie mit der Tabulatortaste zurück zur zuvor ausgewählten Registerkarte und führen Sie die Animation (korrekt) aus.
Die Registerkarte ändert sich also zweimal, zuerst ohne Animation danachsetSelectedIndex
und zum zweiten Mal danachstateChanged
imAnimatedJTabbedPane
.
Ich brauche so etwas wie:
animatedTabbedPane.firePropertyChange("stateChanged", old, new);
Ich möchte nur mit Tabs wechselnstateChanged
Methode, so kann ich ohne Standard tunsetSelectedIndex
Methode. Wie kann ich das machen?
BEARBEITEN Ein kleines Diagramm meines Problems:
Die rote Linie steht für die Sichtbarkeit. Also, wenn der Benutzer nur die Registerkarte wechseltstateChanged
wird genannt,tab 0 ändert sich reibungslos zutab 1. Wenn ich benutzesetSelectedIndex
tab 0 wird sofort durch ersetzttab 1 und erst dann kann ich meine gewünschte animation sehenstateChanged
, so dass die Benutzer einen Blitz sehen.