I have JTabbedPane with fade animation, which is performed when user clicks tabs. To handle animation I override stateChanged
method.
public class A
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.
One approach would be to add an AncestorListener
to each tab's content. Let the listener trigger the desired effect as the tab is added to or removed from visibility.
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();
}
});
}
}