Note that there are some explanatory texts on larger screens.

plurals
  1. POFire stateChanged event on JTabbedPane
    primarykey
    data
    text
    <p>I have JTabbedPane with fade animation, which is performed when user clicks tabs. To handle animation I override <code>stateChanged</code> method.</p> <pre><code>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 &lt; 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(); } </code></pre> <p>}</p> <p>This works great when user clicks tabs manually. <code>stateChanged</code> event is called and tabs are changing with animation.</p> <p>I need to change selected tab from code, so I'm using <code>setSelectedIndex(int)</code> method.</p> <pre><code>public void setSelectedTab(int tab){ animatedTabbedPane.setSelectedIndex(tab); } </code></pre> <p>But right now tab is changed instantly after <code>setSelectedIndex</code> ends - without animation, and then <code>stateChanged</code> method is called, so tab switch back to previously tab selected and perform (correctly) my animation.</p> <p>So tab is changing twice, first without animation after <code>setSelectedIndex</code> and second time after <code>stateChanged</code> in <code>AnimatedJTabbedPane</code>.</p> <p>I need something like:</p> <pre><code> animatedTabbedPane.firePropertyChange("stateChanged", old, new); </code></pre> <p>I want to change tabs only with <code>stateChanged</code> method, so I can do without default <code>setSelectedIndex</code> method. How can I do that?</p> <p><strong>EDIT</strong> A little graph of my problem:</p> <p><img src="https://i.stack.imgur.com/FITDM.png" alt="enter image description here"></p> <p>The red line represents visibility. So when user changes tab only <code>stateChanged</code> is called, <em>tab 0</em> smoothly changes to <em>tab 1</em>. When I use <code>setSelectedIndex</code> <em>tab 0</em> is immediately replaced with <em>tab 1</em> and only then I can see my desired animation from <code>stateChanged</code>, so the users see a flash.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload