JavaFX CheckBoxTreeItem graphic disappear/appear when expanding/collapsing - java

I'm trying to make TreeView with CheckBoxTreeItems. When I collapse/expand a CheckBoxTreeItems the image I set up does not display correctly. I googled but I couldn't find correct answer. On Stack Overflow, I found a similar problem, but I didn't get a valid answer.
E.g
JavaFX CheckBoxTreeItem graphic disappear when siblings collapse
JavaFX CheckBoxTreeItem: Graphic disappears if graph is extended
Any ideas?
public class ClientApplication extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
ImageView folderIcon = new ImageView();
Image folderImage = new Image("image/folder.png");
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", folderIcon);
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), folderIcon);
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
}
enter image description here
I tried to use the ideas provided by #Jai,But when I click the expand/collapse icon, there is still a problem.Attachment is a screenshot.Thanks in advance.
enter image description here

ImageView is a JavaFX control. This means that each instance represents a unique control you see on your screen. You should never use the same instance for multiple locations in your GUI.
On the other hand, Image represents an image (i.e. an array of pixel data), so it is reusable.
This should work:
#Override
public void start(final Stage stage) {
final Image folderImage = new Image("image/folder.png");
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", createImageView(folderImage));
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), createImageView(folderImage));
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
private ImageView createImageView(Image folderImage) {
ImageView folderIcon = new ImageView();
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
return folderIcon;
}

Related

How to change between wireframe and solid in javafx

3d software allow user to change draw mode dinamically. It can be implemented on javafx ?
Changing draw mode with radio buttons
In this approach a Box instance change its DrawMode with radiobuttons.
This is a single class javafx you can try .
App.java
public class App extends Application {
#Override
public void start(Stage stage) {
var perspective = new PerspectiveCamera(true);
perspective.setNearClip(0.1);
perspective.setFarClip(500);
perspective.setTranslateZ(-150);
Shape3D cube = new Box(50, 50, 50);
cube.setCullFace(CullFace.NONE);
cube.setMaterial(new PhongMaterial(Color.CORAL));
var toggleGroup = new ToggleGroup();
var solid = new RadioButton("solid");
solid.setToggleGroup(toggleGroup);
solid.setSelected(true);
var wire = new RadioButton("wireframe");
wire.setToggleGroup(toggleGroup);
var hBox = new HBox(solid, wire);
toggleGroup.selectedToggleProperty().addListener((o) -> {
Toggle selectedToggle = toggleGroup.getSelectedToggle();
if (selectedToggle == solid) {
cube.setDrawMode(DrawMode.FILL);
}
if (selectedToggle == wire) {
cube.setDrawMode(DrawMode.LINE);
}
});
var group3d = new Group(perspective, cube);
var subscene = new SubScene(group3d, 300, 400, true, SceneAntialiasing.BALANCED);
subscene.setCamera(perspective);
var stack = new StackPane(subscene, hBox);
stage.setScene(new Scene(stack, 300, 400));
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Bottom node in stackpane disappearing

Each stack pane is supposed to have two nodes. However the bottom node disappears outside the for loop for the first 2 indices in the stack pane array.
public class Main extends Application {
GridPane images;
StackPane[] stackPane;
ImageView cardBack;
ImageView[] cardImages;
#Override
public void start(Stage stage) throws FileNotFoundException {
images = new GridPane(); images.setAlignment(Pos.CENTER);
images.setVgap(5); images.setHgap(5);
cardBack = new ImageView(new Image(new FileInputStream("images/b1fv.gif")));
cardImages = new ImageView[]{
new ImageView(new Image(new FileInputStream("images/c1.gif"))),
new ImageView(new Image(new FileInputStream("images/c2.gif"))),
new ImageView(new Image(new FileInputStream("images/c3.gif")))
};
final Button[] flip = new Button[cardImages.length];
stackPane = new StackPane[cardImages.length];
for (int i = 0; i < cardImages.length; i++) {
stackPane[i] = new StackPane();
stackPane[i].getChildren().addAll(cardBack, cardImages[i]);
images.add(stackPane[i], i, 0, 1, 1);
flip[i] = new Button("Flip");
GridPane.setHalignment(flip[i], HPos.CENTER);
images.add(flip[i], i, 1, 1, 1);
// Debug
System.out.println(stackPane[i].getChildren().toString());
final int j = i;
flip[j].setOnAction(event -> doFlip(j));
}
// Debug
System.out.println("");
for (StackPane pane : stackPane)
System.out.println(pane.getChildren().toString());
stage.setTitle("Assignment 11");
stage.setScene(new Scene(images, 500,200));
stage.show();
}
void doFlip(int loc) {
// Debug
System.out.println("");
for (StackPane pane : stackPane)
System.out.println(pane.getChildren().toString());
ObservableList<Node> children = stackPane[loc].getChildren();
Node topNode = children.get(children.size()-1);
topNode.toBack();
}
public static void main(String[] args) {
launch(args);
}
}
[ImageView#5e1bc54a[styleClass=image-view], ImageView#25389181[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
[ImageView#25389181[styleClass=image-view]]
[ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
[ImageView#25389181[styleClass=image-view]]
[ImageView#ff7cf97[styleClass=image-view]]
[ImageView#5e1bc54a[styleClass=image-view], ImageView#18b8669d[styleClass=image-view]]
Inside the for loop it displays all objects. However, outside the loop in does not display the bottom nodes except for the last element of array.
You cannot add the same Node instance to multiple parents!
In the top of your loop you have the following line:
stackPane[i].getChildren().addAll(cardBack, cardImages[i]);
The cardBack Node would be added to all StackPanes, but since it can only have one parent, it will be removed from the previous. Javafx has provided a way to reuse Image resources though (which is I imagine the thing you want to achieve). Instead of creating one ImageView, you can cache the Image instance passes in the ImageView constructor. E.g:
cardBack = new Image(new FileInputStream("images/b1fv.gif"));
// some stuff
for (int i = 0; i < cardImages.length; i++) {
stackPane[i] = new StackPane();
stackPane[i].getChildren().addAll(new ImageView(cardBack) , cardImages[i]);
// rest of the loop
}
If you use the Image and ImageView as described above, things will work correctly.

JavaFx pane in pane resizing

How I can resize Pane in GridPane? I'm creating a GUI which is GridPane and a map in it. And when gui change it's size I want to map which is in another Pane to resize. So I've added listners to width and height property of scene and there are generaly working. When I do setTranslateX of map I can see that something changed, but resizing not works at all. It can be caused by fact that map contains from tiles which have their size set. Code of method which create the scene:
private Scene createScene(GridPane root){
Scene scene = new Scene(root, WIDTH_OF_SCENE, HEIGHT_OF_SCENE);
scene.widthProperty().addListener((observableValue, oldSceneWidth, newSceneWidth) -> {
WIDTH_OF_SCENE = newSceneWidth.intValue();
draw();
MAP_PANE.setPrefSize(200, 200); //it's not working
MAP_PANE.setTranslateX(0); //it's working
root.requestLayout();
});
scene.heightProperty().addListener((observableValue, oldSceneHeight, newSceneHeight) ->{
HEIGHT_OF_SCENE = newSceneHeight.intValue();
draw();
root.requestLayout();
});
return scene;
}
And here I'm creating MAP_PANE:
public Pane createContent() {
map = new Pane();
map.setStyle("-fx-background-color: #383838");
// dodawanie pojedynczych kafli do dwuwymiarowej tablicy
for (int y = 0; y < Y_TILES; y++) {
for (int x = 0; x < X_TILES; x++) {
Tile tile = new Tile(x, y);
grid[x][y] = tile;
map.getChildren().addAll(tile);
}
}
return map;
}
And start method:
#Override
public void start(Stage primaryStage) throws Exception{
Map map = new Map();
GridPane root = FXMLLoader.load(getClass().getResource("sample.fxml"));
MAP_PANE = map.createContent();
IMAGE_VIEW = new ImageView();
countScreenSize();
draw();
root.getChildren().addAll(IMAGE_VIEW);
root.getChildren().addAll(MAP_PANE);
primaryStage.setTitle(TITLE);
primaryStage.setScene(createScene(root));
primaryStage.show();
}

Having trouble using getChildren()

Im working on a project for school and I'm having trouble adding a child pane to a parent pane. All the code compiles except when I get to the pane.getChildren().add(Matrix); . Im able to get the code to compile when I have all the code in main, but I really want to have main call a class and create the pane there then add it to the parent pane. Im not to worried about it looking pretty right now, just want to find a way to get it to work. If anyone could help get me going in the right direction I would really appreciate it.
The compiler gives me
Button1.java:34: error: identifier expected
pane.getChildren().add(Matrix);
Button1.java:34: error: ';' expected
pane.getChildren().add(Matrix);
public class Button1 extends Application {
public void start(Stage primaryStage) {
Scene scene = new Scene(pane, 700, 500);
primaryStage.setTitle("3 pains 1 window "); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args) {
Application.launch(args);
}
GridPane pane = new GridPane();
MatrixPane Matrix = new MatrixPane();
pane.getChildren().add(Matrix);
}
class MatrixPane extends Pane {
double HEIGHT = 500;
double WIDTH = 200;
private GridPane pane = new GridPane();
public MatrixPane() {
}
public void fillpane() {
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
TextField text = new TextField(Integer.toString((int)(Math.random() * 2)));
text.setMinWidth(WIDTH / 8.0);
text.setMaxWidth(WIDTH / 10.0);
text.setMinHeight(HEIGHT / 8.0);
text.setMaxHeight(HEIGHT / 10.0);
pane.add(text, j, i);
}
}
}
}
That line have to be inside of a method, I suggest that it should be inside of start
public void start(Stage primaryStage) {
pane.getChildren().add(Matrix);
...
You have missed to include the following section inside a method().

How to apply a blur only to a rectangular area within a pane?

Let's say I've got a StackPane which has a BackgroundImage as background and another StackPane (or another component, if neccessary) as a child. The child covers only a part of the parent StackPane.
I'd like to know how to apply a GaussianBlur just to the area the child covers, so that the BackgroundImageis blurry in this area.
The size of the child changes when the parent is resized. It would be perfect to get a solution that will resize just in time, too.
If you want to do it manually, you can use the snapshot function to create a snapshot image, blur it and apply it to the child every time the parent is resized.
However, invoking snapshot all the time will cause performance loss. I rather suggest you create 2 images, one normal and one blurred, and display a viewport of the blurred one.
Here's a more "complex" example with a circle where the viewport isn't sufficient. The clip method is used in this case:
public class Lens extends Application {
Image image = new Image( "http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/800px-Siberischer_tiger_de_edit02.jpg");
CirclePane circlePane;
#Override
public void start(Stage primaryStage) {
ImageView normalImageView = new ImageView( image);
ImageView blurredImageView = new ImageView( image);
blurredImageView.setEffect(new GaussianBlur( 40));
Group root = new Group();
root.getChildren().addAll( normalImageView);
Scene scene = new Scene( root, 1024, 768);
primaryStage.setScene( scene);
primaryStage.show();
// pane with clipped area
circlePane = new CirclePane( blurredImageView);
makeDraggable( circlePane);
root.getChildren().addAll( circlePane);
}
public static void main(String[] args) {
launch(args);
}
private class CirclePane extends Pane {
ImageView blurredImageView;
ImageView clippedView = new ImageView();
public CirclePane( ImageView blurredImageView) {
this.blurredImageView = blurredImageView;
// new imageview
update();
getChildren().addAll( clippedView);
}
public void update() {
// create circle
Circle circle = new Circle( 200);
circle.relocate( getLayoutX(), getLayoutY());
// clip image by circle
blurredImageView.setClip(circle);
// non-clip area should be transparent
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
// new image from clipped image
WritableImage wim = null;
wim = blurredImageView.snapshot(parameters, wim);
clippedView.setImage( wim);
}
}
// make node draggable
class DragContext {
double x;
double y;
}
public void makeDraggable( Node node) {
final DragContext dragDelta = new DragContext();
node.setOnMousePressed(mouseEvent -> {
dragDelta.x = node.getBoundsInParent().getMinX() - mouseEvent.getScreenX();
dragDelta.y = node.getBoundsInParent().getMinY() - mouseEvent.getScreenY();
});
node.setOnMouseDragged(mouseEvent -> {
node.relocate( mouseEvent.getScreenX() + dragDelta.x, mouseEvent.getScreenY() + dragDelta.y);
circlePane.update();
});
}
}
Just click on the circle and drag it around.

Categories