问题描述
我有JTabbedPane的褪色动画,当用户点击标签时执行。要处理动画,我将覆盖 stateChanged
方法。 public class AnimatedJTabbedPane extends JTabbedPane实现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 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 interrup = false;
if(this.animator.isRunning()){
this.animator.stop();
interrup = true;
}
组件previousComponent = this.getComponentAt(this.previousTabIndex);
this.previousTabImage = this.getGraphicsConfiguration()。createCompatibleImage(
previousComponent.getWidth(),previousComponent.getHeight(),Transparency.TRANSLUCENT);
previousComponent.paint(this.previousTabImage.getGraphics());
组件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();
如果(中断){
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自动生成的方法存根
}
@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自动生成的方法存根
}
@Override
public void timingEvent(float fraction){
this.fraction = fraction;
this.repaint();
}
}
当用户手动单击选项卡时,这很好。
我需要从代码中更改所选的选项卡,所以我将会调用 stateChanged
'使用 setSelectedIndex(int)
方法。
public void setSelectedTab int tab){
animatedTabbedPane.setSelectedIndex(tab);
}
但是现在,标签在 setSelectedIndex
结束 - 没有动画,然后 stateChanged
方法被调用,所以选项卡切换回先前的选项卡,并执行(正确)我的动画。 >
所以标签正在更改两次,首先在 setSelectedIndex
之后没有动画,第二次在 stateChanged
AnimatedJTabbedPane
。
我需要这样的东西:
animatedTabbedPane.firePropertyChange(stateChanged,old,new);
我只想使用 stateChanged
方法,所以我可以做没有默认的 setSelectedIndex
方法。如何做到这一点?
编辑
我的问题的一个小图:
红线代表可见度。所以当用户更改标签只有 stateChanged
被调用时,标签0 顺利地更改为标签1 。当我使用 setSelectedIndex
标签0 立即被替换为标签1 ,只有这样我才能看到我想要的动画从 stateChanged
,所以用户看到一个闪光。
我的问题的原因。
这是线程问题,而不是动画本身。我在 EDT 之外打电话 setSelectedIndex
,所以我的JTabbedPane立即更新,然后执行了 EDT 的动画。
anserw是:
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);
}
更改 EDT 中的标签不会不需要闪现了。
I have JTabbedPane with fade animation, which is performed when user clicks tabs. To handle animation I override stateChanged
method.
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();
}
}
This works great when user clicks tabs manually. stateChanged
event is called and tabs are changing with animation.
I need to change selected tab from code, so I'm using setSelectedIndex(int)
method.
public void setSelectedTab(int tab){
animatedTabbedPane.setSelectedIndex(tab);
}
But right now tab is changed instantly after setSelectedIndex
ends - without animation, and then stateChanged
method is called, so tab switch back to previously tab selected and perform (correctly) my animation.
So tab is changing twice, first without animation after setSelectedIndex
and second time after stateChanged
in AnimatedJTabbedPane
.
I need something like:
animatedTabbedPane.firePropertyChange("stateChanged", old, new);
I want to change tabs only with stateChanged
method, so I can do without default setSelectedIndex
method. How can I do that?
EDITA little graph of my problem:
The red line represents visibility. So when user changes tab only stateChanged
is called, tab 0 smoothly changes to tab 1. When I use setSelectedIndex
tab 0 is immediately replaced with tab 1 and only then I can see my desired animation from stateChanged
, so the users see a flash.
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.
这篇关于Fire State在JTabbedPane上更改事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!