JavaFX UI won't update

public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
displayBoard(presenter.getBoard());
selector = new SelectorView(new SelectorPresenter());
presenter.selectionProperty().addListener((_, _, newValue) -> {
getChildren().remove(selector);
if (newValue == null)
return;
add(selector, newValue.x(), newValue.y());
});
}
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
displayBoard(presenter.getBoard());
selector = new SelectorView(new SelectorPresenter());
presenter.selectionProperty().addListener((_, _, newValue) -> {
getChildren().remove(selector);
if (newValue == null)
return;
add(selector, newValue.x(), newValue.y());
});
}
The line getChildren().remove get's executed on the application thread and does remove the child. But the UI doesn't update/repaint because when I resize my window the selector disappears. When I run my app with debug the ui properly updates but when I don't run it with debug it doesn't
33 Replies
JavaBot
JavaBot3w ago
This post has been reserved for your question.
Hey @Noah | Nowipi! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
iamnotknown
iamnotknown3w ago
i have no idea
JavaBot
JavaBot3w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
dan1st
dan1st3w ago
Why should it update when resizing?
Noah | Nowipi
Noah | NowipiOP3w ago
It should update when i call remove But it doesn't It does when you manually update the ui with something like resizing the window
dan1st
dan1st3w ago
Did you check whether remove is called? Does the size actually change?
Noah | Nowipi
Noah | NowipiOP3w ago
Yes the size changes And yes remove gets called It does only seem to happen if the property changes it's value to null It's a javafx objectproperty btw
dan1st
dan1st3w ago
Can you try replacing the element by an "empty" element? instead of just removing it
Noah | Nowipi
Noah | NowipiOP3w ago
Not at the moment but I will tomorrow That would be strange if that would work though
JavaBot
JavaBot3w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Noah | Nowipi
Noah | NowipiOP3w ago
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
selector = new SelectorView(new SelectorPresenter());

displayBoard(presenter.getBoard());
presenter.selectionProperty().addListener((_, oldValue, newValue) -> {
getChildren().remove(selector);
if (oldValue != null)
add(new ImageView(), oldValue.x(), oldValue.y());

if (newValue != null) {
add(selector, newValue.x(), newValue.y());
}
});
}
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
selector = new SelectorView(new SelectorPresenter());

displayBoard(presenter.getBoard());
presenter.selectionProperty().addListener((_, oldValue, newValue) -> {
getChildren().remove(selector);
if (oldValue != null)
add(new ImageView(), oldValue.x(), oldValue.y());

if (newValue != null) {
add(selector, newValue.x(), newValue.y());
}
});
}
this works putting an empty image at the old place but that's a hacky solution
dan1st
dan1st3w ago
Does using that mechanism make any difference? https://stackoverflow.com/a/72322665/10871900
Stack Overflow
In JavaFx, how to remove a specific node from a gridpane with the c...
If I know the specific coordinate of the node I am trying to remove, let's say "col:3, row: 4", how can I remove the node in column 3 and row 4? Is there a built-in method I can use in Java?
dan1st
dan1st3w ago
like maybe it doesn't like the remove()
Noah | Nowipi
Noah | NowipiOP3w ago
removeIf doesn't work either but I found layout() and layoutChildren() but they also both don't work maybe it has something to do with that in the same grid cell there are multiple imageViews I have an image of a gem and the selector in the same cell because when I remove all images from the same cell the selector does disappear but when I only remove the selector the selector does not appear The SelectorView also isn't a normal ImageView
public class SelectorView extends ImageView {

private final SpriteAnimation animation;

public SelectorView(SelectorPresenter presenter) {
super(new Image(ResourceManager.getResource(presenter.getImagePath())));
animation = new SpriteAnimation(
this,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
}
}
public class SelectorView extends ImageView {

private final SpriteAnimation animation;

public SelectorView(SelectorPresenter presenter) {
super(new Image(ResourceManager.getResource(presenter.getImagePath())));
animation = new SpriteAnimation(
this,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
}
}
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
selector = new SelectorView(new SelectorPresenter());

displayBoard(presenter.getBoard());
presenter.selectionProperty().addListener((_, oldValue, newValue) -> {

selector.getAnimation().stop();
getChildren().remove(selector);
layout();

if (newValue != null) {
add(selector, newValue.x(), newValue.y());
selector.getAnimation().play();
}
});
}
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final SelectorView selector;

public BoardView() {
presenter = new BoardPresenter(this);
selector = new SelectorView(new SelectorPresenter());

displayBoard(presenter.getBoard());
presenter.selectionProperty().addListener((_, oldValue, newValue) -> {

selector.getAnimation().stop();
getChildren().remove(selector);
layout();

if (newValue != null) {
add(selector, newValue.x(), newValue.y());
selector.getAnimation().play();
}
});
}
dan1st
dan1st3w ago
Do you have a custom add method?
Noah | Nowipi
Noah | NowipiOP3w ago
no
dan1st
dan1st3w ago
Can you show a minimal reproducer? instead of replacing it with an empty ImageView, you could try replacing it with an empty Node or whatever
Noah | Nowipi
Noah | NowipiOP3w ago
I can't seem to reproduce it
package nowipi.bejeweled;

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import nowipi.bejeweled.domain.Vector2;

public class JavaFXProblem extends Application {

private static final int WIDTH = 8;
private static final int HEIGHT = 8;

private final ObjectProperty<Vector2> selection = new SimpleObjectProperty<>();
private final ImageView selector;

public JavaFXProblem() {
selector = new ImageView("https://d2bzx2vuetkzse.cloudfront.net/unshoppable_producs/a948fba6-5a77-4256-bc0d-65429a880128.png");
selector.setFitWidth(64);
selector.setFitHeight(64);
}

@Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
fillGrid(grid);
selectionProperty().addListener((_, _, newValue) -> {
System.out.println(newValue);
grid.getChildren().remove(selector);
grid.layout();

if (newValue != null) {
grid.add(selector, newValue.x(), newValue.y());
}
});
primaryStage.setScene(new Scene(grid));
primaryStage.show();
}

private void fillGrid(GridPane grid) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
ImageView imageView = new ImageView("https://cdn-icons-png.flaticon.com/512/226/226777.png");
imageView.setFitWidth(64);
imageView.setFitHeight(64);

final int finalX = x;
final int finalY = y;
imageView.addEventHandler(MouseEvent.MOUSE_CLICKED, _ -> click(finalX, finalY));

grid.add(imageView, x, y);
}
}
}
package nowipi.bejeweled;

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import nowipi.bejeweled.domain.Vector2;

public class JavaFXProblem extends Application {

private static final int WIDTH = 8;
private static final int HEIGHT = 8;

private final ObjectProperty<Vector2> selection = new SimpleObjectProperty<>();
private final ImageView selector;

public JavaFXProblem() {
selector = new ImageView("https://d2bzx2vuetkzse.cloudfront.net/unshoppable_producs/a948fba6-5a77-4256-bc0d-65429a880128.png");
selector.setFitWidth(64);
selector.setFitHeight(64);
}

@Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
fillGrid(grid);
selectionProperty().addListener((_, _, newValue) -> {
System.out.println(newValue);
grid.getChildren().remove(selector);
grid.layout();

if (newValue != null) {
grid.add(selector, newValue.x(), newValue.y());
}
});
primaryStage.setScene(new Scene(grid));
primaryStage.show();
}

private void fillGrid(GridPane grid) {
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
ImageView imageView = new ImageView("https://cdn-icons-png.flaticon.com/512/226/226777.png");
imageView.setFitWidth(64);
imageView.setFitHeight(64);

final int finalX = x;
final int finalY = y;
imageView.addEventHandler(MouseEvent.MOUSE_CLICKED, _ -> click(finalX, finalY));

grid.add(imageView, x, y);
}
}
}
private void click(int gridX, int gridY) {
if (getSelection() == null) {
setSelection(gridX, gridY);
} else {
if (isAdjacent(getSelection().x(), getSelection().y(), gridX, gridY)) {
selection.set(null);
} else {
setSelection(gridX, gridY);
}
}
}

private boolean isAdjacent(int aX, int aY, int bX, int bY) {
int dx = Math.abs(aX - bX);
int dy = Math.abs(aY - bY);
return (dx == 1 && dy == 0) || (dx == 0 && dy == 1);
}

public void setSelection(int x, int y) {
selection.set(new Vector2(x, y));
}

public Vector2 getSelection() {
return selection.get();
}

public ObjectProperty<Vector2> selectionProperty() {
return selection;
}

public static void main(String[] args) {
launch();
}
private void click(int gridX, int gridY) {
if (getSelection() == null) {
setSelection(gridX, gridY);
} else {
if (isAdjacent(getSelection().x(), getSelection().y(), gridX, gridY)) {
selection.set(null);
} else {
setSelection(gridX, gridY);
}
}
}

private boolean isAdjacent(int aX, int aY, int bX, int bY) {
int dx = Math.abs(aX - bX);
int dy = Math.abs(aY - bY);
return (dx == 1 && dy == 0) || (dx == 0 && dy == 1);
}

public void setSelection(int x, int y) {
selection.set(new Vector2(x, y));
}

public Vector2 getSelection() {
return selection.get();
}

public ObjectProperty<Vector2> selectionProperty() {
return selection;
}

public static void main(String[] args) {
launch();
}
This works fine although clicks don't always register Than it has to be something that has to do with it having animations
dan1st
dan1st3w ago
ig maybe stuff doesn't disappear during animations If you are using Timelines, you might have the issue of it not being removed: https://dev.java/learn/javafx-animations/#timeline but I can't do much except guessing if I can't reproduce it
Noah | Nowipi
Noah | NowipiOP3w ago
I am using Transition
Noah | Nowipi
Noah | NowipiOP3w ago
Netopyr GmbH
Creating a Sprite Animation with JavaFX
While most of my posts so far dealt with JavaFX properties and bindings, today I want to write about another part of the JavaFX runtime I also work on: the animation API. In this article I will explai
Noah | Nowipi
Noah | NowipiOP3w ago
it's definitely the remove call but I think it's a JavaFX bug the grid isn't redrawing because I have another image under it
dan1st
dan1st3w ago
What do you mean with having another image under it? What happens if you remove it and add another element at a different position?
Noah | Nowipi
Noah | NowipiOP3w ago
The grid is filled with imageviews
dan1st
dan1st3w ago
Might be interesting to see
Noah | Nowipi
Noah | NowipiOP3w ago
than it updates correctly
dan1st
dan1st3w ago
When you say "under", do you mean "below" or "behind"?
Noah | Nowipi
Noah | NowipiOP3w ago
below oh no soryy behind
dan1st
dan1st3w ago
Does it still happen without the image behind? btw you could try not removing any ImageViews at all but just do yourImageView.setImage(yourNewImage)
Noah | Nowipi
Noah | NowipiOP3w ago
I can try
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final GemView[][] gems;

public BoardView() {
presenter = new BoardPresenter(this);

presenter.selectionProperty().addListener((_, oldValue, newValue) -> {
if (oldValue != null) {
GemView view = getGem(oldValue.x(), oldValue.y());
view.deselect();
}

if (newValue != null) {
GemView view = getGem(newValue.x(), newValue.y());
view.select();
}
});

gems = presenter.getGems();

for (int y = 0; y < gems.length; y++) {
for (int x = 0; x < gems[y].length; x++) {
GemView view = getGem(x, y);

final int gemX = x;
final int gemY = y;
view.addEventHandler(MouseEvent.MOUSE_CLICKED, _ -> presenter.click(gemX, gemY));

add(view, x, y);
}
}
}

public GemView getGem(int x, int y) {
return gems[y][x];
}
}
public class BoardView extends GridPane {

private final BoardPresenter presenter;
private final GemView[][] gems;

public BoardView() {
presenter = new BoardPresenter(this);

presenter.selectionProperty().addListener((_, oldValue, newValue) -> {
if (oldValue != null) {
GemView view = getGem(oldValue.x(), oldValue.y());
view.deselect();
}

if (newValue != null) {
GemView view = getGem(newValue.x(), newValue.y());
view.select();
}
});

gems = presenter.getGems();

for (int y = 0; y < gems.length; y++) {
for (int x = 0; x < gems[y].length; x++) {
GemView view = getGem(x, y);

final int gemX = x;
final int gemY = y;
view.addEventHandler(MouseEvent.MOUSE_CLICKED, _ -> presenter.click(gemX, gemY));

add(view, x, y);
}
}
}

public GemView getGem(int x, int y) {
return gems[y][x];
}
}
fixed it
public class GemView extends StackPane {


private final SpriteAnimation selectAnimation;
private final ImageView gem;
private final SelectorView selector;

public GemView(GemPresenter presenter) {
gem = new ImageView(new Image(ResourceManager.getResource(presenter.getImagePath())));
selector = new SelectorView();
getChildren().add(gem);
getChildren().add(selector);

selectAnimation = new SpriteAnimation(
gem,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
selectAnimation.setCycleCount(Animation.INDEFINITE);
}

public void select() {
selectAnimation.play();
selector.select();
}

public void deselect() {
selectAnimation.stop();
selectAnimation.interpolate(0);
selector.deselect();
}
}
public class GemView extends StackPane {


private final SpriteAnimation selectAnimation;
private final ImageView gem;
private final SelectorView selector;

public GemView(GemPresenter presenter) {
gem = new ImageView(new Image(ResourceManager.getResource(presenter.getImagePath())));
selector = new SelectorView();
getChildren().add(gem);
getChildren().add(selector);

selectAnimation = new SpriteAnimation(
gem,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
selectAnimation.setCycleCount(Animation.INDEFINITE);
}

public void select() {
selectAnimation.play();
selector.select();
}

public void deselect() {
selectAnimation.stop();
selectAnimation.interpolate(0);
selector.deselect();
}
}
public class SelectorView extends ImageView {

private final Image image;
private final SpriteAnimation animation;

public SelectorView() {
this(new SelectorPresenter());
}

private SelectorView(SelectorPresenter presenter) {
image = new Image(ResourceManager.getResource(presenter.getImagePath()));
animation = new SpriteAnimation(
this,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
animation.setCycleCount(Animation.INDEFINITE);
}

public void select() {
setImage(image);
animation.play();
}

public void deselect() {
animation.stop();
setImage(null);
}
}
public class SelectorView extends ImageView {

private final Image image;
private final SpriteAnimation animation;

public SelectorView() {
this(new SelectorPresenter());
}

private SelectorView(SelectorPresenter presenter) {
image = new Image(ResourceManager.getResource(presenter.getImagePath()));
animation = new SpriteAnimation(
this,
Duration.millis(1000),
presenter.getFrameCount(),
presenter.getColumnCount(),
presenter.getOffsetX(),
presenter.getOffsetY(),
presenter.getSpriteWidth(),
presenter.getSpriteHeight()
);
animation.setCycleCount(Animation.INDEFINITE);
}

public void select() {
setImage(image);
animation.play();
}

public void deselect() {
animation.stop();
setImage(null);
}
}
I treated ImageView's like they were images and that's not what they are for Now I treat them as things that display an image and it works I still think I encountered a JavaFX bug though but this is a way cleaner solution ty this helped a lot!
dan1st
dan1st3w ago
if you can create a minimal reproducer, you could try reporting it though if you show me before, I could maybe check about it actually being some intentional thing if you don't want to: you don't have to also it could be fixed by updating JavaFX
JavaBot
JavaBot3w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
JavaBot
JavaBot3w ago
Post Closed
This post has been closed by <@270107388244262912>.

Did you find this page helpful?