Reputation: 13
I am having difficulty trying to solve this, I am currently trying to figure out how to change the ImageView to another ImageView when I press a certain Key on my keyboard but I have no idea how to, I have already looked around almost everywhere I can think of but haven't got a clue.
Heres the code, this is a character class:
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import javafx.animation.Animation;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Character extends Application{
private static final int COLUMNS = 3;
private static final int COUNT = 3;
private static final int WIDTH = 48;
private static final int HEIGHT = 50;
ImageView imgView;
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
imgView = characterStill();
root.setOnKeyPressed(e -> {
if(e.getCode().equals(KeyCode.RIGHT)){
try {
imgView = characterWalking();
} catch (IOException ex) {}
}
});
root.setOnKeyReleased(e -> {
if(e.getCode().equals(KeyCode.RIGHT)){
try {
imgView = characterStill();
} catch (IOException ex) {}
}
});
root.getChildren().add(imgView);
Scene scene = new Scene(root, Menu.WIDTH, Menu.HEIGHT, Color.GREENYELLOW);
primaryStage.setScene(scene);
primaryStage.show();
}
public ImageView characterStill() throws IOException{
InputStream is = Files.newInputStream(Paths.get("C:\\Users\\Javier\\Desktop\\StickHero\\StillNinja.png"));
Image characterStill = new Image(is);
ImageView stillView = new ImageView(characterStill);
return stillView;
}
public ImageView characterWalking() throws IOException{
final InputStream is = Files.newInputStream(Paths.get("C:\\Users\\Javier\\Desktop\\StickHero\\WalkingNinja.png"));
final Image characterWalking = new Image(is);
ImageView charView = new ImageView(characterWalking);
charView.setViewport(new Rectangle2D(0, 0, WIDTH, HEIGHT));
final Animation animation = new AnimationGen(charView, Duration.millis(300), COUNT, COLUMNS, 0, 0, WIDTH, HEIGHT);
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
return charView;
}
}
Upvotes: 1
Views: 1109
Reputation: 209724
In Java, all objects are accessed via a reference. It is important to keep the distinction between the object in memory, and the reference to the object, clear.
When you execute
new ImageView(characterStill);
a new ImageView
object is created in memory. When you then (effectively) do
imgView = new ImageView(characterStill);
you assign the variable imgView
a reference to that object. You can think of the reference as the memory location of the object (though in reality it doesn't necessarily have to be implemented that way).
What happens in your code at initialization is effectively the following:
imgView = new ImageView(characterStill);
root.getChildren().add(imgView);
So imgView
contains a reference to an ImageView
object displaying your characterStill
image. You then pass that reference to the child list of root
, so now the child list of root
contains a reference to that same ImageView
object.
Now, when the user presses the RIGHT key, you (effectively) execute
imgView = new ImageView(characterWalking);
This creates a new ImageView
object in memory, and assigns a reference to it (think: memory location of this new object) to the variable imgView
.
However, the child list of root
hasn't changed: it still contains the original reference to the first ImageView
object. So nothing changes in your UI.
You could fix this by replacing the child list of root
with the newly created ImageView
, i.e.:
root.setOnKeyPressed(e -> {
if(e.getCode().equals(KeyCode.RIGHT)){
try {
imgView = characterWalking();
root.getChildren().setAll(imgView);
} catch (IOException ex) {}
}
});
However, this is not very efficient. On every key press, you create a brand new object in memory, from an image freshly loaded from the hard drive. Then you discard the previous object and put the new object in the UI.
A better way is just to use a single ImageView
object, and replace the image which it displays. You can do this by calling
imgView.setImage(...);
To make things even more efficient, instead of loading the image from disk every time, you could just load the images at startup and then reuse them. This code looks like
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import javafx.animation.Animation;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Character extends Application{
private static final int COLUMNS = 3;
private static final int COUNT = 3;
private static final int WIDTH = 48;
private static final int HEIGHT = 50;
private ImageView imgView;
private Image characterStill ;
private Image characterWalking ;
private Animation animation ;
public void start(Stage primaryStage) throws Exception {
imgView = new ImageView();
characterStill = loadCharacterStill();
characterWalking = loadCharacterWalking();
imgView.setViewport(new Rectangle2D(0, 0, WIDTH, HEIGHT));
animation = new AnimationGen(charView, Duration.millis(300), COUNT, COLUMNS, 0, 0, WIDTH, HEIGHT);
animation.setCycleCount(Animation.INDEFINITE);
imgView.setImage(characterStill);
Group root = new Group();
root.setOnKeyPressed(e -> {
if(e.getCode().equals(KeyCode.RIGHT)){
imgView.setImage(characterWalking);
animation.play();
}
});
root.setOnKeyReleased(e -> {
if(e.getCode().equals(KeyCode.RIGHT)){
imgView.setImage(characterStill);
animation.stop();
}
});
root.getChildren().add(imgView);
Scene scene = new Scene(root, Menu.WIDTH, Menu.HEIGHT, Color.GREENYELLOW);
primaryStage.setScene(scene);
primaryStage.show();
}
public Image loadCharacterStill() throws IOException{
InputStream is = Files.newInputStream(Paths.get("C:\\Users\\Javier\\Desktop\\StickHero\\StillNinja.png"));
Image characterStill = new Image(is);
return characterStill ;
}
public Image loadCharacterWalking() throws IOException{
final InputStream is = Files.newInputStream(Paths.get("C:\\Users\\Javier\\Desktop\\StickHero\\WalkingNinja.png"));
final Image characterWalking = new Image(is);
return characterWalking ;
}
}
Obviously, since I don't have access to your images or your AnimationGen
class, I haven't tested this; it should give you the idea though.
Upvotes: 2