JavaFX How do you bind an animation to a certain value? - java

I have made an application with JavaFX, where you have a picture with animated stuff in it, based on certain values in the app. The only problem I have: I don't really know, how to bind the values to the animations, so the animations move, based on the value put in. For example: if the value is 10, the animation should move fast. If the value is 1 the animation should move slow. Here is the code for the animation (it is smoke, coming out of a house):
smoke = new Image(HydroControl.class.getResource("/imgs/smoke.png").toExternalForm());
smokeView = new ImageView(smoke);
smokeView.setX(-190);
smokeView.setY(60);
Path path3 = new Path();
path3.getElements().add(new MoveTo(1,-60));
path3.getElements().add(new CubicCurveTo(0, 0, 0, 0, 0, 0));
PathTransition pathTransition3 = new PathTransition();
pathTransition3.setDuration(Duration.millis(2000));
pathTransition3.setPath(path3);
pathTransition3.setNode(smokeView);
pathTransition3.setCycleCount(Timeline.INDEFINITE);
pathTransition3.setAutoReverse(true);
pathTransition3.play();
Here is the code with the values:
public class PresentationModel {
private final DoubleProperty waterValue = new SimpleDoubleProperty();
private final DoubleProperty powerValue = new SimpleDoubleProperty();
private final BooleanProperty isOnValue = new SimpleBooleanProperty();
public double getWaterValue() {
return waterValue.get();
}
public DoubleProperty waterValueProperty() {
return waterValue;
}
public void setWaterValue(double waterValue) {
this.waterValue.set(waterValue);
}
public double getPowerValue() {
return powerValue.get();
}
public DoubleProperty powerValueProperty() {
return powerValue;
}
public void setPowerValue(double powerValue) {
this.powerValue.set(powerValue);
}
public boolean isIsOnValue() {
return isOnValue.get();
}
public BooleanProperty isOnValueProperty() {
return isOnValue;
}
public void setIsOnValue(boolean isOnValue) {
this.isOnValue.set(isOnValue);
}
}
I would be really glad if you could help me. Thank you.

Bind the properties of your transition to the values of your model with a calculation from the Bindings class. For example:
pathTransition3.durationProperty().bind(Bindings.multiply(Bindings.multiply(model.powerProperty(), model.waterValueProperty()), 500d));
model.isOnValueProperty().addListener((v, o, n) -> {
if (n) {
pathTransition3.play();
} else {
pathTransition3.pause();
}
});

Related

JavaFx Group contents position getting changed upon transformation

I'm simulating a compass where I need to display current angular position upon reception of angular data from another source(via network). But somehow the circle group is getting shifted upon applying transformation to Text node based upon angular position. This is a sample code
MainApp.java
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.scene.transform.Rotate;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class MainApp extends Application {
static BorderPane borderPane;
static Group clock;
static Group angStatus;
public static Circle clockCircle;
public static Line angHand;
public static Text angText;
public static Rotate angRotate;
public static Label angLabel;
public static void main(String[] args) {
borderPane = new BorderPane();
clock = new Group();
angStatus = new Group();
clockCircle = new Circle();
clockCircle.centerXProperty().bind(borderPane.layoutXProperty());
clockCircle.centerYProperty().bind(borderPane.layoutYProperty());
clockCircle.setRadius(360);
clockCircle.setFill(Color.RED);
angHand = new Line();
angHand.startXProperty().bind(clockCircle.centerXProperty());
angHand.startYProperty().bind(clockCircle.centerYProperty());
angText = new Text();
angRotate = new Rotate();
angRotate.pivotXProperty().bind(angText.xProperty());
angRotate.pivotYProperty().bind(angText.yProperty());
angText.getTransforms().addAll(angRotate);
angLabel = new Label();
angLabel.layoutXProperty().bind(borderPane.layoutXProperty());
angLabel.layoutYProperty().bind(borderPane.layoutYProperty());
clock.getChildren().addAll(clockCircle, angHand, angText);
angStatus.getChildren().addAll(angLabel);
borderPane.setCenter(clock);
borderPane.setBottom(angStatus);
DataReceiver objDataReceiver = new DataReceiver();
Thread dataRecvThread = new Thread(objDataReceiver, "DATARECVR");
dataRecvThread.start();
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("CLOCK");
primaryStage.setMaximized(true);
primaryStage.setScene(new Scene(borderPane, Screen.getPrimary().getVisualBounds().getWidth(), Screen.getPrimary().getVisualBounds().getHeight()));
primaryStage.show();
}
}
DataReceiver.java
import javafx.application.Platform;
import java.time.Instant;
import static java.lang.Thread.sleep;
public class DataReceiver implements Runnable {
public static int deg;
DataReceiver() {
deg = 0;
}
public void run() {
while(true) {
long startTime = Instant.now().toEpochMilli();
deg++;
while(deg >= 360)
deg -= 360;
while(deg < 0)
deg += 360;
long endTime = Instant.now().toEpochMilli();
Platform.runLater(() -> {
MainApp.angHand.endXProperty().bind(MainApp.clockCircle.radiusProperty().multiply(Math.sin(Math.toRadians(deg))));
MainApp.angHand.endYProperty().bind(MainApp.clockCircle.radiusProperty().multiply(-Math.cos(Math.toRadians(deg))));
MainApp.angText.xProperty().bind(MainApp.angHand.endXProperty().add(10 * Math.sin(Math.toRadians(deg))));
MainApp.angText.yProperty().bind(MainApp.angHand.endYProperty().subtract(10 * Math.cos(Math.toRadians(deg))));
MainApp.angText.setText(String.valueOf(deg));
MainApp.angRotate.setAngle(deg);
MainApp.angLabel.setText("Angle: " + deg);
});
try {
sleep(1000 - (endTime - startTime));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I'm using jdk-13.0.1 and javafx-sdk-11.0.2
The problem here is the fact that Group itself is non-resizeable, but changes it's own size to fit the contents. Modifying the transformations of the text results in the bounds of the Group changing horizontally and/or vertically which in turn makes the parent layout reposition the group to keep it centered. Depending on your needs you may want wrap the clock in a parent not doing this (Pane). If you want to keep the center of the circle centered, you'll probably need to implement your own layout.
Notes:
I don't recommend doing this using a Thread. Instead do this using AnimationTimer or similar utilities provided by JavaFX.
Bindings are only necessary for dynamic updates. If you just want to set values, it's the wrong choice.
There is the remainder operator (%) which could deal with the logic of one of the while loops. Furthermore the second loop is not actually needed, since the value of deg is never decreased below 0.
I wouldn't recommend putting the logic using threads in the main method. The way you implement the logic could result in an exception, if Platform.runLater is called before the toolkit has been started. Better initialize this kind of logic from Application.start.
static should be avoided, if possible, since it makes controlling the flow of data more complicated. And what if you want to display 2 clocks for different timezones? There's no way of reusing the class, if it relies on static data in the way your classes do.
A binding like the following makes no sense: borderPane is the root of the scene and therefore will keep the position (0,0); furthermore angLabel is a descendant of the borderPane. I recommend not wrapping the label in a group any use the static BorderPane.alignment property to tell borderPane how to position the node.
angLabel.layoutXProperty().bind(borderPane.layoutXProperty());
angLabel.layoutYProperty().bind(borderPane.layoutYProperty());
The following example makes Clock a Control with a property of type LocalTime and calculates the positions of the children itself:
public class Clock extends Control {
private final ObjectProperty<LocalTime> time = new SimpleObjectProperty<>(this, "time", LocalTime.MIDNIGHT) {
#Override
public void set(LocalTime newValue) {
// make sure the value is non-null
super.set(newValue == null ? LocalTime.MIDNIGHT : newValue);
}
};
public ObjectProperty<LocalTime> timeProperty() {
return time;
}
public LocalTime getTime() {
return time.get();
}
public void setTime(LocalTime value) {
time.set(value);
}
#Override
protected Skin<?> createDefaultSkin() {
return new ClockSkin(this);
}
}
public class ClockSkin extends SkinBase<Clock> {
private static final double SPACE = 20;
private static final double FACTOR = 360d / 60;
private final Circle face;
private final Line secondsHand;
private final Rotate rotate;
private final Text secondsText;
public ClockSkin(Clock control) {
super(control);
face = new Circle(360, Color.RED);
// line straight up from center to circle border
secondsHand = new Line();
secondsHand.endXProperty().bind(face.centerXProperty());
secondsHand.endYProperty().bind(face.centerYProperty().subtract(face.getRadius()));
secondsHand.startXProperty().bind(face.centerXProperty());
secondsHand.startYProperty().bind(face.centerYProperty());
secondsText = new Text();
rotate = new Rotate();
rotate.pivotXProperty().bind(face.centerXProperty());
rotate.pivotYProperty().bind(face.centerYProperty());
secondsHand.getTransforms().add(rotate);
secondsText.getTransforms().add(rotate);
registerChangeListener(control.timeProperty(), (observable) -> {
LocalTime value = (LocalTime) observable.getValue();
update(value);
control.requestLayout();
});
getChildren().addAll(face, secondsHand, secondsText);
update(control.getTime());
}
protected void update(LocalTime time) {
int seconds = time.getSecond();
secondsText.setText(Integer.toString(seconds));
rotate.setAngle(seconds * FACTOR);
}
#Override
protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
// center face
face.setCenterX(contentX + SPACE + contentWidth / 2);
face.setCenterY(contentY + SPACE + contentHeight / 2);
// position text
secondsText.setX(contentX + SPACE + (contentWidth - secondsText.prefWidth(-1)) / 2);
secondsText.setY(face.getCenterY() - face.getRadius() - SPACE / 2);
}
#Override
protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset,
double leftInset) {
return 2 * (SPACE + face.getRadius()) + leftInset + rightInset;
}
#Override
protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
return 2 * (SPACE + face.getRadius()) + topInset + bottomInset;
}
#Override
protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset,
double leftInset) {
return computeMinWidth(height, topInset, rightInset, bottomInset, leftInset);
}
#Override
protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset,
double leftInset) {
return computeMinHeight(width, topInset, rightInset, bottomInset, leftInset);
}
#Override
public void dispose() {
getChildren().clear();
super.dispose();
}
}
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane borderPane = new BorderPane();
Clock clock = new Clock();
clock.setTime(LocalTime.now());
Label angLabel = new Label();
BorderPane.setAlignment(angLabel, Pos.TOP_LEFT);
borderPane.setCenter(clock);
borderPane.setBottom(angLabel);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
LocalTime time = LocalTime.now();
clock.setTime(time);
angLabel.setText(formatter.format(time));
}
};
timer.start();
primaryStage.setTitle("CLOCK");
primaryStage.setMaximized(true);
primaryStage.setScene(new Scene(borderPane));
primaryStage.show();
}
Note that here the separation between the logic for updating the visuals and updating the data is done much more cleanly than in your code. In general you want to prevent access of other classes to internal logic, since this prevents outside interference that could possibly break your control.

Setting ImageView in JavaFX based on a gif animation

I am fairly new to programming and have recently encountered a problem that I have not found a solution for online. I have created an ImageView in FXML and gave it an FXid of "gif1". I am using code from this stackoverflow post but I tried modifying it so that it would fit my needs. I put the entirety of the code in a separate java file that I called "Gif.java". Typically, "Gif.java" uses an hbox and other non applicable methods to set the ImageView. I removed those because I will be using an existing FXML document so there is no need to create a new one. In my code, I call on "Gif.java" and expect a returned ImageView. However, when I set my ImageView (gif1) to the returned ImageView, it doesn't update on the screen.
Here is the link to the gif post: How I can stop an animated GIF in JavaFX?
Here is my code that I use to update gif1:
#FXML
private void setUp(){
Gif newGif = new Gif("rightrock.gif"); // Creates object newGif and passes through path to gif
gif1 = newGif.returnImage2(); // Sets gif1 to returned ImageView
}
Here is the return code in Gif.java:
public class Gif{
private Animation ani;
private ImageView test;
public Gif(String image) {
// TODO: provide gif file, ie exchange banana.gif with your file
ani = new AnimatedGif(getClass().getResource(image).toExternalForm(), 1000);
ani.setCycleCount(1);
ani.play();
Button btPause = new Button( "Pause");
btPause.setOnAction( e -> ani.pause());
Button btResume = new Button( "Resume");
btResume.setOnAction( e -> ani.play());
}
public void returnImage(ImageView x){
test = x; // Sets ImageView test to parameter x
}
public ImageView returnImage2() {
return test; // Return instance field test
}
public static void main(String[] args) {
launch(args);
}
public class AnimatedGif extends Animation {
public AnimatedGif( String filename, double durationMs) {
GifDecoder d = new GifDecoder();
d.read( filename);
Image[] sequence = new Image[ d.getFrameCount()];
for( int i=0; i < d.getFrameCount(); i++) {
WritableImage wimg = null;
BufferedImage bimg = d.getFrame(i);
sequence[i] = SwingFXUtils.toFXImage( bimg, wimg);
}
super.init( sequence, durationMs);
}
}
public class Animation extends Transition {
private ImageView imageView;
private int count;
private int lastIndex;
private Image[] sequence;
private Animation() {
}
public Animation( Image[] sequence, double durationMs) {
init( sequence, durationMs);
}
private void init( Image[] sequence, double durationMs) {
this.imageView = new ImageView(sequence[0]);
this.sequence = sequence;
this.count = sequence.length;
setCycleCount(1);
setCycleDuration(Duration.millis(durationMs));
setInterpolator(Interpolator.LINEAR);
}
protected void interpolate(double k) {
final int index = Math.min((int) Math.floor(k * count), count - 1);
if (index != lastIndex) {
imageView.setImage(sequence[index]);
lastIndex = index;
}
}
public ImageView getView() {
returnImage(imageView); // This runs returnImage with the ImageView that I want to set
return imageView;
}
}
Any help would be greatly appreciated!

How to create interactive graphic with Vaadin?

I want to develop a simple interactive game (like arcanoid). I already have implemented a menu and different views, and now I need to develop the actually game (draw flying ball, some movable platform) and I don't know how to do this. I need something like canvas where I can draw my graphic each frame.
I have tryed to implement this with Canvas and Timer. But it doesn't want update graphic itself, but only when user clicks on screen or similar. Also I saw com.google.gwt.canvas.client.Canvas, but I cannot understand how to use it in Vaadin application.
So my question is next: is it possible to draw some graphic each frame with high framerate in any way? If possible, how can I do this?
P.S. I use the Vaadin 7.3.3.
ADDED LATER:
Here is a link to my educational project with implementation below.
I'll be glad if it helps someone.
ORIGINAL ANSWER:
Well... I found the solution myself. First of all, I have created my own widget - "client side" component (according to this article).
Client side part:
public class GWTMyCanvasWidget extends Composite {
public static final String CLASSNAME = "mycomponent";
private static final int FRAMERATE = 30;
public GWTMyCanvasWidget() {
canvas = Canvas.createIfSupported();
initWidget(canvas);
setStyleName(CLASSNAME);
}
Connector:
#Connect(MyCanvas.class)
public class MyCanvasConnector extends AbstractComponentConnector {
#Override
public Widget getWidget() {
return (GWTMyCanvasWidget) super.getWidget();
}
#Override
protected Widget createWidget() {
return GWT.create(GWTMyCanvasWidget.class);
}
}
Server side part:
public class MyCanvas extends AbstractComponent {
#Override
public MyCanvasState getState() {
return (MyCanvasState) super.getState();
}
}
Then I just add MyCanvas component on my View:
private void createCanvas() {
MyCanvas canvas = new MyCanvas();
addComponent(canvas);
canvas.setSizeFull();
}
And now I can draw anything on Canvas (on client side in GWTMyCanvasWidget) with great performance =). Example:
public class GWTMyCanvasWidget extends Composite {
public static final String CLASSNAME = "mycomponent";
private static final int FRAMERATE = 30;
private Canvas canvas;
private Platform platform;
private int textX;
public GWTMyCanvasWidget() {
canvas = Canvas.createIfSupported();
canvas.addMouseMoveHandler(new MouseMoveHandler() {
#Override
public void onMouseMove(MouseMoveEvent event) {
if (platform != null) {
platform.setCenterX(event.getX());
}
}
});
initWidget(canvas);
Window.addResizeHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent resizeEvent) {
resizeCanvas(resizeEvent.getWidth(), resizeEvent.getHeight());
}
});
initGameTimer();
resizeCanvas(Window.getClientWidth(), Window.getClientHeight());
setStyleName(CLASSNAME);
platform = createPlatform();
}
private void resizeCanvas(int width, int height) {
canvas.setWidth(width + "px");
canvas.setCoordinateSpaceWidth(width);
canvas.setHeight(height + "px");
canvas.setCoordinateSpaceHeight(height);
}
private void initGameTimer() {
Timer timer = new Timer() {
#Override
public void run() {
drawCanvas();
}
};
timer.scheduleRepeating(1000 / FRAMERATE);
}
private void drawCanvas() {
canvas.getContext2d().clearRect(0, 0, canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());
drawPlatform();
}
private Platform createPlatform() {
Platform platform = new Platform();
platform.setY(Window.getClientHeight());
return platform;
}
private void drawPlatform() {
canvas.getContext2d().fillRect(platform.getCenterX() - platform.getWidth() / 2, platform.getY() - 100, platform.getWidth(), platform.getHeight());
}
}

Java Android Augmented Reality Application Image Coordinates

i am currently new to augmented reality programming and i would like to ask a question regarding the cameraView. My objective is to display an clickable imageButton at a specific real-life coordinate and display it in a cameraView. In this case, the thing that i want to display inside my cameraView(Which is a world) is my button. I tried using Wikitude/ AndAR/ Layar API before i decided that it was a hassle to call its permission for usage and I am currently using DroidAR as a library and reference. However i can't seem to find a way to display what i want correctly. I would like to seek help regarding this issue. Please advise me or guide me the correct way to achieve it. Thank you very much ! Below are my current codes using the droidAR library SDK.
public class DisplayAR extends Setup {
private static final float MIN_DIST = 15f;
private static final float MAX_DIST = 55f;
private Button b = null;
protected static final String LOG_TAG = "StaticDemoSetup";
World world;
GLCamera camera;
private TimeModifier timeModifier;
#Override
public void _a_initFieldsIfNecessary() {
// allow the user to send error reports to the developer:
}
#Override
public void _b_addWorldsToRenderer(GL1Renderer renderer,
GLFactory objectFactory, GeoObj currentPosition) {
camera = new GLCamera(new Vec(0, 0, 1));
world = new World(camera);
timeModifier = new TimeModifier(1);
RenderList l = new RenderList();
timeModifier.setChild(l);
world.add(timeModifier);
initI9Tests(world);
addTestGeoObj(world, camera);
renderer.addRenderElement(world);
}
private void addTestGeoObj(World w, GLCamera c) {
GeoObj o = new GeoObj();
w.add(o);
}
private void initI9Tests(World w) {
{
// transform android ui elements into opengl models:
b = new Button(getActivity());
b.setText("L.311");
MeshComponent button = GLFactory.getInstance().newTexturedSquare("buttonId", IO.loadBitmapFromView(b));
button.addChild(new AnimationFaceToCamera(camera, 0.5f));
button.setScale(new Vec(10, 10, 10));
button.setColor(Color.red());
button.setOnClickCommand(new CommandShowToast(getActivity(), "THIS IS L.311"));
GeoObj treangleGeo = new GeoObj();
treangleGeo.setVirtualPosition(new Vec(MIN_DIST, MAX_DIST, 0.0f));
treangleGeo.setComp(button);
w.add(treangleGeo);
}
}
#Override
public void _c_addActionsToEvents(EventManager eventManager,
CustomGLSurfaceView arView, SystemUpdater updater) {
ActionWASDMovement wasdAction = new ActionWASDMovement(camera, 25f,
50f, 20f);
ActionRotateCameraBuffered rotateAction = new ActionRotateCameraBuffered(
camera);
eventManager.addOnLocationChangedAction(new ActionCalcRelativePos(
world, camera));
updater.addObjectToUpdateCycle(wasdAction);
updater.addObjectToUpdateCycle(rotateAction);
arView.addOnTouchMoveAction(wasdAction);
eventManager.addOnOrientationChangedAction(rotateAction);
eventManager.addOnTrackballAction(new ActionMoveCameraBuffered(camera,
5, 25));
}
#Override
public void _d_addElementsToUpdateThread(SystemUpdater worldUpdater) {
// add the created world to be updated:
worldUpdater.addObjectToUpdateCycle(world);
}
#Override
public void _e2_addElementsToGuiSetup(GuiSetup guiSetup, Activity activity) {
guiSetup.setBottomMinimumHeight(50);
guiSetup.setBottomViewCentered();
}
}
try to use wikitude library for augmented reality at www.wikitude.com it has sample example simpleArbrowser is what u wanted

Piccolo zoomable interface, how to change text when zooming

I'm experimenting with some Piccolo to create a zoomable interface.
I'm creating a rectangle on a canvas with some PText on it. Now when zooming, I want to change the text to something different.
I've done this in my initialize:
//
//specify the current Piccolo PCanvas
//
m_canvas = getCanvas();
m_canvas.removeInputEventListener(m_canvas.getPanEventHandler());
//m_canvas.addInputEventListener(new ClickAndDragHandler(m_canvas));
//
//add nodes to the collection -> adding to the collection = adding to the canvas
//
m_nodecollection = new NodeCollection(m_canvas);
RectangleNode node_links = new RectangleNode();
node_links.setBounds(10, 10, 500, 500);
m_nodecollection.addNode(node_links);
RectangleNode node_rechts = new RectangleNode();
node_rechts.setBounds(600,10,500,500);
m_nodecollection.addNode(node_rechts);
PImage node_arrowLeft = new PImage("left.gif");
node_arrowLeft.setBounds(600, 550, node_arrowLeft.getWidth(), node_arrowLeft.getHeight());
m_nodecollection.addNode(node_arrowLeft);
PImage node_arrowRight = new PImage("right.gif");
node_arrowRight.setBounds(680, 550, node_arrowRight.getWidth(), node_arrowRight.getHeight());
m_nodecollection.addNode(node_arrowRight);
m_nodecollection.connectNodesWithLine(node_rechts, node_arrowRight, true);
m_nodecollection.connectNodesWithLine(node_rechts, node_arrowLeft, true);
PText node_text = new PText("Zoomlevel Not Supported");
node_text.setBounds(180,150, node_text.getWidth(), node_text.getHeight());
m_nodecollection.connectNodesWithLine(node_links, node_text, true);
m_nodecollection.addNode(node_text);
node_links.addChild(node_text);
node_links.setCollection(m_nodecollection);
Created my own rectangle class with the whole nodecollection and PText as membervar.
public class RectangleNode extends PNode{
private Rectangle2D m_rectangle;
private NodeCollection collection;
private PText text;
public RectangleNode()
{
m_rectangle = new Rectangle2D.Double();
}
public Rectangle2D getRectangle()
{
if(m_rectangle == null)
m_rectangle = new Rectangle2D.Double();
return m_rectangle;
}
public boolean setBounds(double x, double y, double w, double h)
{
if(super.setBounds(x, y, w, h))
{
m_rectangle.setFrame(x, y, w, h);
return true;
}
return false;
}
public void setCollection(NodeCollection collection)
{
this.collection = collection;
}
public void setText(PText text)
{
this.text = text;
}
public void paint(PPaintContext paintcontext)
{
Graphics2D g2 = paintcontext.getGraphics();
//niet ingezoomd
if(paintcontext.getScale() <= 0.2)
g2.setPaint(Color.BLACK);
//half ingezoomd
if(paintcontext.getScale() > 0.2 && paintcontext.getScale() < 0.7)
{
g2.setPaint(Color.BLACK);
}
//volledig ingezoomd
if(paintcontext.getScale() > 0.7)
{
g2.setPaint(Color.RED);
g2.fill(getRectangle());
g2.setPaint(Color.BLACK);
g2.draw(getRectangle());
}
}
}
Now, I thought I could change the text like this: text.setText("Tester"); but It doesn't work, also when for example settext and then add the node to collection then it displays over the current text with a huge error...
Can someone help me please?
kind regards,
Consider posting the whole example as SSCCE, looks like some parts of the code are missing. It is not clear how you actually execute setText.
It may be easier to compose existing nodes and listen to events fired from camera. Consider the following example that draws a rectangle with some text which gets updated according to a zoom level:
import java.awt.Color;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import edu.umd.cs.piccolo.PCamera;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.nodes.PText;
import edu.umd.cs.piccolo.util.PPaintContext;
import edu.umd.cs.piccolox.PFrame;
public class TestRectZoom extends PFrame {
public TestRectZoom() {
super("TestRectZoom", false, null);
}
public void initialize() {
getCanvas().setInteractingRenderQuality(
PPaintContext.HIGH_QUALITY_RENDERING);
getCanvas().setDefaultRenderQuality(
PPaintContext.HIGH_QUALITY_RENDERING);
getCanvas().setAnimatingRenderQuality(
PPaintContext.HIGH_QUALITY_RENDERING);
final PPath rect = PPath.createRectangle(100, 100, 200, 200);
rect.setPaint(Color.GREEN);
getCanvas().getLayer().addChild(rect);
final PText text = new PText(getZoomLevelString());
rect.addChild(text);
text.centerFullBoundsOnPoint(rect.getBounds().getCenterX(), rect
.getBounds().getCenterY());
getCanvas().getCamera().addPropertyChangeListener(
PCamera.PROPERTY_VIEW_TRANSFORM, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
text.setText(getZoomLevelString());
if (getCanvas().getCamera().getViewScale() > 0.9) {
rect.setPaint(Color.GREEN);
} else {
rect.setPaint(Color.RED);
}
}
});
}
private String getZoomLevelString() {
return "Zoom level:"
+ String.format("%.2f", getCanvas().getCamera().getViewScale());
}
public static void main(final String[] args) {
new TestRectZoom();
}
}
That's how the result looks like:
You are looking for semantic zooming available on the Piccolo Patterns page.
Pattern 17: Semantic Zooming
http://www.piccolo2d.org/learn/patterns.html
I solved the problem like Aqua suggested.

Categories

Resources