Hello, I've been trying to fix a bug I just found using Transitions and
ComponentMouseListeners. You can take, for example, the ScaleTransition
I just submitted to the dev mailing list, although this should apply to
any transition.
For this example, I'll use the ScaleTransition in a
ComponentMouseListener, as follows:
import java.util.Arrays;
import java.util.Collection;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.ComponentMouseListener;
public class ZoomComponentMouseListener implements ComponentMouseListener {
private ScaleTransition scaleTransition = new ScaleTransition();
public ZoomComponentMouseListener(Component targetComponent) {
scaleTransition.addComponent(targetComponent);
}
public boolean mouseMove(Component component, int x, int y) {
return false;
}
public void mouseOver(Component component) {
if (scaleTransition.isRunning()) {
scaleTransition.reverse();
} else {
scaleTransition.setReversed(false);
scaleTransition.start();
}
}
public void mouseOut(Component component) {
if (scaleTransition.isRunning()) {
scaleTransition.reverse();
} else {
scaleTransition.setReversed(true);
scaleTransition.start();
}
}
public void setZoom(float zoom) {
scaleTransition.setZoom(zoom);
}
}
When this listener is attached to a Component, like an ImageView for
example, if you get through the ImageView quickly with the mouse pointer
and then cross it again quickly, the method
Transition#getPercentComplete will get screwed, the second time the
transition is started getPercentComplete will report 1 when it should
report 0. I've tested this many times, before calling Transition#start,
getPercentComplete reports 0, when calling start and checking the value
of getPercentComplete from the Transition#update method it reports 1.
I've got no clue on what's happening here, placing a breakpoint inside
the Transition#start method reports currentTime - startTime == 0, but
checking again when it gets to the Transition#update method currentTime
- startTime == 1.
Perhaps I've anticipated on saying this is a bug for Transitions,
perhaps is my code what's causing problems, but I just don't have a clue
on how to fix this.
Please, if anybody's able to reproduce this, let me know so we can find
a solution. I've attached the ScaleTransition here in case there are
users not subscribed to the dev mailing list.
Thanks in advance!
Edgar Merino
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.devpower.pivot;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.effects.Decorator;
import org.apache.pivot.wtk.effects.ScaleDecorator;
/**
* This transition provides a "zoom" effect for components that use it.
*
* @author emerino
*/
public class ScaleTransition extends Transition {
private class CustomScaleDecorator extends ScaleDecorator {
private float initialScaleX = 1.0f;
private float initialScaleY = 1.0f;
public void setInitialScales(ScaleDecorator decorator) {
initialScaleX = decorator.getScaleX();
initialScaleY = decorator.getScaleY();
}
public float getInitialScaleX() {
return initialScaleX;
}
public float getInitialScaleY() {
return initialScaleY;
}
}
private static final int DEFAULT_DURATION = 200;
private static final int DEFAULT_RATE = 28;
private Map<Component, CustomScaleDecorator> componentDecoratorMap =
Collections.synchronizedMap(new HashMap<Component, CustomScaleDecorator>());
private boolean reversed;
private float zoom = 0.3f;
public ScaleTransition() {
this(DEFAULT_DURATION, DEFAULT_RATE);
}
public ScaleTransition(int duration, int rate) {
super(duration, rate);
}
public Set<Component> getComponents() {
return componentDecoratorMap.keySet();
}
public void addComponent(Component component) {
if (component == null) {
throw new IllegalArgumentException("Component cannot be null");
}
if (!componentDecoratorMap.containsKey(component)) {
CustomScaleDecorator scaleDecorator = new CustomScaleDecorator();
for (Decorator decorator : component.getDecorators()) {
if (decorator instanceof ScaleDecorator) {
scaleDecorator.setInitialScales(scaleDecorator);
break;
}
}
componentDecoratorMap.put(component, scaleDecorator);
component.getDecorators().add(scaleDecorator);
}
}
public void addComponents(Collection<Component> components) {
for (Component c : components) {
addComponent(c);
}
}
public void setZoom(float zoom) {
if (isRunning()) {
throw new IllegalStateException("Transition in progress");
}
this.zoom = zoom;
}
public void setReversed(boolean reversed) {
if (isRunning()) {
throw new IllegalStateException("Transition in progress");
}
this.reversed = reversed;
}
@Override
protected void update() {
float scaleX = 0;
float scaleY = 0;
CustomScaleDecorator scaleDecorator = null;
for (Component component : componentDecoratorMap.keySet()) {
scaleDecorator = componentDecoratorMap.get(component);
if (!reversed) {
scaleX = scaleDecorator.getInitialScaleX() + (zoom * getPercentComplete());
scaleY = scaleDecorator.getInitialScaleY() + (zoom * getPercentComplete());
} else {
scaleX = (scaleDecorator.getInitialScaleX() + zoom) - (zoom * getPercentComplete());
scaleY = (scaleDecorator.getInitialScaleY() + zoom) - (zoom * getPercentComplete());
}
scaleDecorator.setScaleX(scaleX);
scaleDecorator.setScaleY(scaleY);
component.repaint();
}
}
public void removeComponent(Component component) {
if (componentDecoratorMap.containsKey(component)) {
component.getDecorators().remove(componentDecoratorMap.remove(component));
}
}
public void clearComponents() {
for (Component c : componentDecoratorMap.keySet()) {
removeComponent(c);
}
}
}