JavaFX drag and drop not working correctly - javafx

Im doing a drag and drop test with two Imageviews in a gridpane. My problem is that when i complete the drag and drop and move target imageview to source imageview and release the mouse i wrongly end up with it showing the picture from "img2" and not the picture from "img1". When i comment out the "setOnDragExited" method i end up with the correct image "img1" Any suggestions would be appreciated.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Test extends Application
{
Image img1 = new Image("/graphics/hvid/hvidBonde.png");
Image hvidTom = new Image("/graphics/hvid/hvidTom.png");
Image sortTom = new Image("/graphics/sort/sortTom.png");
ImageView source = new ImageView(img1);
Image img2 = new Image("/graphics/sort/sortBonde.png");
ImageView target = new ImageView(img2);
GridPane root = new GridPane();
#Override
public void start(Stage primaryStage) throws Exception
{
root.add(source, 1, 1);
root.add(target, 2, 2);
Scene scene = new Scene(root, 800, 800, Color.WHITE);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
source.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event)
{
Dragboard db = source.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
content.putString(source.toString());
db.setContent(content);
event.consume();
}
});
target.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
if (event.getGestureSource() != target &&
event.getDragboard().hasString())
{
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
}
});
target.setOnDragEntered(new EventHandler<DragEvent>() {
public void handle(DragEvent event)
{
if (event.getGestureSource() != target &&
event.getDragboard().hasString())
{
target.setImage(source.getImage());
}
event.consume();
}
});
target.setOnDragExited(new EventHandler<DragEvent>()
{
public void handle(DragEvent event)
{
target.setImage(img2);
event.consume();
}
});
target.setOnDragDropped(new EventHandler<DragEvent>() {
public void handle(DragEvent event)
{
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString())
{
target.setImage(source.getImage());
success = true;
}
event.setDropCompleted(success);
event.consume();
}
});
source.setOnDragDone(new EventHandler<DragEvent>() {
public void handle(DragEvent event)
{
if (event.getTransferMode() == TransferMode.MOVE)
{
source.setImage(hvidTom);
}
event.consume();
}
});
}
}

Here is a sample app you can test with. In my opinion, you should not put your event handlers on the ImageViews. Put them on the nodes the ImageViews are in.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Test extends Application
{
Image img1 = new Image("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png");
#Override
public void start(Stage primaryStage) throws Exception
{
ImageView source = new ImageView();
ImageView target = new ImageView();
source.setImage(img1);
StackPane stackPaneLeft = new StackPane(source);
stackPaneLeft.setStyle("-fx-background-color: yellow");
stackPaneLeft.setPrefSize(400, 800);
stackPaneLeft.setOnDragDetected((MouseEvent event)
-> {
Dragboard db = source.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
content.putImage(source.getImage());
db.setContent(content);
event.consume();
});
stackPaneLeft.setOnDragDone((DragEvent event) -> {
if (event.getTransferMode() == TransferMode.MOVE) {
source.setImage(null);
}
event.consume();
});
StackPane stackPaneRight = new StackPane(target);
stackPaneRight.setStyle("-fx-background-color: blue");
stackPaneRight.setPrefSize(400, 800);
stackPaneRight.setOnDragOver((DragEvent event)
-> {
if (event.getGestureSource() != target
&& event.getDragboard().hasImage()) {
event.acceptTransferModes(TransferMode.ANY);
}
event.consume();
});
stackPaneRight.setOnDragEntered((DragEvent event)
-> {
if (event.getGestureSource() != target
&& event.getDragboard().hasImage()) {
target.setImage(source.getImage());
}
event.consume();
});
stackPaneRight.setOnDragExited((DragEvent event)
-> {
if (target.getImage() != null && !event.isDropCompleted()) {
target.setImage(null);
}
event.consume();
});
stackPaneRight.setOnDragDropped((DragEvent event)
-> {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasImage()) {
target.setImage(source.getImage());
success = true;
}
event.setDropCompleted(success);
event.consume();
});
HBox root = new HBox(stackPaneLeft, stackPaneRight);
Scene scene = new Scene(root, 800, 800, Color.WHITE);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
}

Related

How to Create a Custom Control in JavaFX

Here I created my own control, with a canvas and ScrollBar. I didn't manage to correctly intercept the keyboard shortcuts or key pressed. When adding another component to the scene (here a TextField, commented), no keyboard events are received. Maybe I missed something about the focus?
Also, I had to add some --export to Gradle, to avoid some errors with the module.
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
repositories {
mavenCentral()
}
javafx {
version = "15.0.1"
modules = [ 'javafx.controls', 'javafx.graphics' ]
}
run {
jvmArgs = ['--add-exports=javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED',
'--add-exports=javafx.controls/com.sun.javafx.scene.control.inputmap=ALL-UNNAMED']
}
mainClassName = 'com.wisecoders.textpane.CustomControlApp'
package com.wisecoders.textpane;
import com.sun.javafx.scene.control.behavior.BehaviorBase;
import com.sun.javafx.scene.control.inputmap.InputMap;
import com.sun.javafx.scene.control.inputmap.KeyBinding;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class CustomControlApp extends Application {
private final BorderPane root = new BorderPane();
private final Scene scene = new Scene(root, 300, 250);
#Override
public void start(Stage stage) {
stage.setTitle("Sample Canvas");
root.setTop( new TextField());
MyControl control = new MyControl();
root.setCenter(control);
stage.setScene(scene);
stage.sizeToScene();
Platform.runLater( control::requestFocus );
stage.show();
}
public static void main(String[] args) {
launch(args);
}
class MyControl extends Control {
private final StringBuilder buffer = new StringBuilder();
public MyControl(){
setPrefSize(400, 400 );
setFocusTraversable(true);
setOnMouseClicked(ev-> requestFocus());
requestFocus();
setOnKeyTyped(ev-> { if ( !ev.isShortcutDown() ){
addTextToBuffer( ev.getCharacter() );
}});
}
public void addTextToBuffer( String str ){
buffer.append( str );
((MyControlSkin)getSkin()).paintCanvas();
}
public String getText(){ return buffer.toString(); }
#Override protected Skin<?> createDefaultSkin() {
return new MyControlSkin(this);
}
}
class MyControlSkin extends SkinBase<MyControl> {
final BorderPane borderPane = new BorderPane();
final ScrollBar rightScroll = new ScrollBar();
final Canvas canvas = new Canvas();
final MyControlBehavior behavior;
public MyControlSkin(MyControl control) {
super(control);
behavior = new MyControlBehavior( control );
rightScroll.setOrientation(Orientation.VERTICAL);
borderPane.setRight( rightScroll );
borderPane.setCenter(canvas);
canvas.setWidth( 150);
canvas.setHeight( 150 );
getChildren().add( borderPane );
paintCanvas();
}
public void paintCanvas(){
GraphicsContext gr = canvas.getGraphicsContext2D();
gr.clearRect( 0,0, canvas.getWidth(), canvas.getHeight());
gr.setFill( Color.BLACK);
gr.fillText( "Buff:" + getSkinnable().getText(), 30, 20 );
}
#Override
public void dispose() {
super.dispose();
behavior.dispose();
getChildren().removeAll();
}
}
class MyControlBehavior extends BehaviorBase<MyControl> {
final InputMap<MyControl> inputMap;
public MyControlBehavior(MyControl control) {
super(control);
this.inputMap = createInputMap();
addDefaultMapping( inputMap, new InputMap.KeyMapping(new KeyBinding(KeyCode.C).shortcut().ctrl(), e-> copy() ) );
}
public void copy(){
final Clipboard clipboard = Clipboard.getSystemClipboard();
final ClipboardContent content = new ClipboardContent();
content.putString( getNode().getText() );
clipboard.setContent(content);
}
#Override
public InputMap<MyControl> getInputMap() {
return inputMap;
}
}
}

JavaFX progress indicator stop spinning when heavy load runs

I am trying to implement busy indicator using ProgressIndicator. But when the heavy load starts the indicator freezes. A sample code is shown below.
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class BusyIcon {
private static Stage busyWindow;
public static void showBusyIcon(final Stage stage) {
busyWindow = new Stage(StageStyle.UNDECORATED);
//busyWindow.setOpacity(.3);
busyWindow.initOwner(stage);
busyWindow.initModality(Modality.WINDOW_MODAL);
StackPane stackPane = new StackPane();
final ProgressIndicator loadingIndicator = new ProgressIndicator();
loadingIndicator.setVisible(true);
stackPane.getChildren().add(loadingIndicator);
Scene scene = new Scene(stackPane, 100, 100);
scene.setFill(Color.TRANSPARENT);
busyWindow.setScene(scene);
ChangeListener<Number> widthListener = (observable, oldValue, newValue) -> {
double stageWidth = newValue.doubleValue();
busyWindow.setX(stage.getX() + stage.getWidth() / 2 - stageWidth / 2);
};
ChangeListener<Number> heightListener = (observable, oldValue, newValue) -> {
double stageHeight = newValue.doubleValue();
busyWindow.setY(stage.getY() + stage.getHeight() / 2 - stageHeight / 2);
};
busyWindow.widthProperty().addListener(widthListener);
busyWindow.heightProperty().addListener(heightListener);
busyWindow.setOnShown(e -> {
busyWindow.widthProperty().removeListener(widthListener);
busyWindow.heightProperty().removeListener(heightListener);
});
busyWindow.show();
}
public static void closeBusyIcon(final Stage stage) {
if (busyWindow != null) {
busyWindow.close();
busyWindow = null;
}
}
}
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import preloader.BusyIcon;
public class QuestionExample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Task Progress Tester");
StackPane testPane = new StackPane();
Button b = new Button("Load");
b.setOnAction((event) -> {
BusyIcon.showBusyIcon(primaryStage);
Task t = new Task() {
#Override
protected Object call() throws Exception {
try {
addNewComponent(testPane);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
};
t.setOnSucceeded((ev) -> {
BusyIcon.closeBusyIcon(primaryStage);
});
new Thread(t).start();
});
testPane.getChildren().add(b);
primaryStage.setScene(new Scene(testPane, 300, 250));
primaryStage.show();
}
private void addNewComponent(Pane testPane) {
try {
/**
* Some heavy load work will run here
*/
Thread.sleep(2000);
Platform.runLater(() -> {
try {
/**
* We need to change the fx controls here
*/
Button b1 = new Button("New Component");
testPane.getChildren().add(b1);
/**
* This may take some time
*/
Thread.sleep(2000);
} catch (Exception ex) {
ex.printStackTrace();
}
});
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
BusyIcon is used for showing progress indicator. If we are not using the Platform.runLater then it will throw 'Not in FX thread' exception will be thrown.
I suggest you try ControlsFX MaskerPane. The key is to set the MaskerPane visible and move it to the front of an AnchorPane before the task runs. When the task finishes, set it invisible and move it to the back of the AnchorPane.
DEMO:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.MaskerPane;
/**
*
* #author blj0011
*/
public class MaskerPaneTest extends Application
{
#Override
public void start(Stage primaryStage)
{
MaskerPane mpDeterminate = new MaskerPane();
MaskerPane mpUndeterminate = new MaskerPane();
mpDeterminate.setVisible(false);
mpUndeterminate.setVisible(false);
Button btn = new Button();
btn.setText("Determinate");
btn.setOnAction((ActionEvent event) -> {
mpDeterminate.setVisible(true);
mpDeterminate.toFront();
Task<Void> task = new Task<Void>()
{
#Override
protected Void call() throws Exception
{
for (int i = 0; i < 40000000; i++) {
//Do something
updateProgress(i, 40000000);
}
return null;
}
};
mpDeterminate.progressProperty().bind(task.progressProperty());
task.setOnSucceeded((workerStateEvent) -> {
mpDeterminate.setVisible(false);
mpDeterminate.toBack();
});
new Thread(task).start();
});
Button btn2 = new Button();
btn2.setText("Undeterminate");
btn2.setOnAction((ActionEvent event) -> {
mpUndeterminate.setVisible(true);
mpUndeterminate.toFront();
Task<Void> task = new Task<Void>()
{
#Override
protected Void call() throws Exception
{
for (int i = 0; i < 100000; i++) {
//Do something
System.out.println("working!");
}
return null;
}
};
mpUndeterminate.progressProperty().bind(task.progressProperty());
task.setOnSucceeded((workerStateEvent) -> {
mpUndeterminate.setVisible(false);
mpUndeterminate.toBack();
});
new Thread(task).start();
});
StackPane root = new StackPane(mpDeterminate, mpUndeterminate, new VBox(btn, btn2));
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}

Javafx: Checkbox Listener on newly added item in treeView

I asked this question but didn't get any response. Javafx: Check box Listener example Please i need help with this problem of mine. code is
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.HashMap;
import java.util.Map;
public class Main extends Application {
private static int rootNr = 0;
private static int coordinateNr = 0;
public static void main(String[] args) {
launch(args);
}
static final Map<TreeItem<String>, BorderPane> map = new HashMap<>();
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
TreeItem<String> tree = new TreeItem<>("Main System");
TreeItem<String> item1 = new TreeItem<>("Roots");
TreeView<String> treeView = new TreeView<>(tree);
treeView.setOnMouseClicked((event) -> {
TreeItem<String> treeItem = treeView.getSelectionModel().getSelectedItem();
if (treeItem.getChildren().stream().anyMatch(child -> child.getValue().startsWith("C"))) {
root.setCenter(getRootsPanel(treeItem.getValue()));
}else {
root.setCenter(map.get(treeItem));
}
});
treeView.setCellFactory(p -> new AddMenuTreeCell());
tree.setExpanded(true);
root.setLeft(treeView);
tree.getChildren().add(item1);
Scene scene = new Scene(root, 700, 500);
primaryStage.setTitle("Tree View");
primaryStage.setScene(scene);
primaryStage.show();
}
private static class AddMenuTreeCell extends TextFieldTreeCell<String> {
private ContextMenu menu = new ContextMenu();
private TextField textField;
public AddMenuTreeCell() {
MenuItem newitem1 = new MenuItem("Insert Roots");
MenuItem newitem2 = new MenuItem("Insert Coordinates");
menu.getItems().addAll(newitem1, newitem2);
newitem1.setOnAction(arg0 -> {
TreeItem<String> item3 = new TreeItem<>("Root" + rootNr++);
getTreeItem().getChildren().add(item3);
});
newitem2.setOnAction(arg0 -> {
TreeItem<String> newLeaf = new TreeItem<>("Coordinates" + coordinateNr++);
TreeItem<String> uxItem1 = new TreeItem<>("X");
map.put(uxItem1, getrightPane1());
TreeItem<String> uyItem1 = new TreeItem<>("y");
map.put(uyItem1, getrightPane1());
newLeaf.getChildren().add(uxItem1);
newLeaf.getChildren().add(uyItem1);
getTreeItem().getChildren().add(newLeaf);
});
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (!isEditing()) {
setText(item);
setGraphic(getTreeItem().getGraphic());
if (!(getTreeItem().isLeaf() && getTreeItem().getParent() == null)) {
setContextMenu(menu);
}
}
}
}
}
private static BorderPane getrightPane1() {
TextField textf1 = new TextField();
TextField textf2 = new TextField();
BorderPane root1 = new BorderPane();
VBox vbox = new VBox(20);
vbox.setPadding(new Insets(10));
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
textf1.setPrefWidth(100);
textf1.setPromptText("Enter Height");
textf1.setOnKeyReleased(event -> {
if (textf1.getText().length() > 0 && textf2.getText().length() > 0) {
Rectangle rect1 = new Rectangle();
rect1.setHeight(Double.parseDouble(textf1.getText()));
rect1.setWidth(Double.parseDouble(textf2.getText()));
rect1.setFill(null);
rect1.setStroke(Color.BLUE);
root1.setCenter(rect1);
}
});
textf2.setPrefWidth(100);
textf2.setPromptText("Enter Width");
textf2.setOnKeyReleased(event -> {
if (textf1.getText().length() > 0 && textf2.getText().length() > 0) {
Rectangle rect2 = new Rectangle();
rect2.setHeight(Double.parseDouble(textf1.getText()));
rect2.setWidth(Double.parseDouble(textf2.getText()));
rect2.setFill(null);
rect2.setStroke(Color.RED);
root1.setCenter(rect2);
}
});
if (textf1.getText().length() > 0 && textf2.getText().length() > 0 && root1.getCenter() == null) {
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setCenter(rect);
}
h1.getChildren().addAll(new Label("Y1:"), textf1);
h2.getChildren().addAll(new Label("X1:"), textf2);
vbox.getChildren().addAll(h1, h2);
root1.setLeft(vbox);
return root1;
}
private static BorderPane getRootsPanel(String root) {
BorderPane root2 = new BorderPane();
HBox hbox = new HBox(10);
hbox.setPadding(new Insets(40));
hbox.setAlignment(Pos.TOP_CENTER);
CheckBox box1 = new CheckBox("Change order");
CheckBox box2 = new CheckBox("Change View");
box1.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
// rect1.setStroke(Color.RED);
// rect2.setStroke(Color.BLUE);
} else {
// rect1.setStroke(Color.BLUE);
// rect2.setStroke(Color.RED);
}
});
box2.selectedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
} else {
}
});
VBox vbox = new VBox(30, box1,box2);
for (Map.Entry<TreeItem<String>, BorderPane> entry : map.entrySet()) {
if (entry.getKey().getParent().getParent().getValue().equals(root)) {
Rectangle rect1 = (Rectangle) entry.getValue().getCenter();
if (rect1 != null) {
Rectangle rect2 = new Rectangle();
rect2.setWidth(rect1.getWidth());
rect2.setHeight(rect1.getHeight());
rect2.setFill(rect1.getFill());
rect2.setStroke(rect1.getStroke());
Platform.runLater(() -> hbox.getChildren().addAll(rect2));
}
}
}
hbox.getChildren().add(vbox);
Platform.runLater(() -> root2.setLeft(hbox));
return root2;
}
}
TreeView in which user can add roots and coordinates. coordinate's rectangle are shown horizontally in root.
User need first check box to change rectangles order(like 1 2 3 to 3 2 1) & second to change view (horizontal to vertical). If there were only 2 Leafs this can be done with code given in Comments (i didn't put 2nd box code in comment because one i have can only use 2 leafs).
These check-boxes should have effect on all generated rectangles not just 2.
This would be a big help. thank you

JavaFx: Adding TreeItem in TreeView again

A TreeView must have TreeItems added. Here is my code:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Main extends Application
{
private BorderPane border;
#SuppressWarnings("unchecked")
#Override
public void start(Stage primaryStage)
{
border = new BorderPane();
Scene scene = new Scene(border,600,300);
primaryStage.setTitle("BorderPane");
primaryStage.setScene(scene);
primaryStage.show();
TreeItem<String> tree = new TreeItem<String>("Main System");
TreeItem<String> item2 = new TreeItem<String>("Roots");
TreeItem<String> item2Child1 = new TreeItem<String>("UX");
TreeItem<String> item2Child2 = new TreeItem<String>("UY");
item2.getChildren().addAll(item2Child1,item2Child2);
item2.setExpanded(true);
tree.setExpanded(true);
tree.getChildren().add(item2);
TreeView<String> treeView = new TreeView<String>(tree);
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new AddMenuTreeCell();
}
});
VBox box3 = new VBox();
treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem>() {
#Override
public void changed(ObservableValue<? extends TreeItem> observable, TreeItem oldValue, TreeItem newValue) {
if (newValue.getValue().equals(item2Child1.getValue())) {
box3.getChildren().add(getrightPane1());
} else {
int i = box3.getChildren().size();
if (i > 0) {
box3.getChildren().remove(0);
}
}
}
});
VBox box4 = new VBox();
treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem>() {
#Override
public void changed(ObservableValue<? extends TreeItem> observable, TreeItem oldValue, TreeItem newValue) {
if (newValue.getValue().equals(item2Child2.getValue())) {
box4.getChildren().add(getrightPane2());
} else {
int i = box4.getChildren().size();
if (i > 0) {
box4.getChildren().remove(0);
}
}
}
});
VBox box2 = new VBox();
treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem>() {
#Override
public void changed(ObservableValue<? extends TreeItem> observable, TreeItem oldValue, TreeItem newValue) {
if (newValue.getValue().equals(item2.getValue())) {
box2.getChildren().add(getrightPane3());
} else {
int i = box2.getChildren().size();
if (i > 0) {
box2.getChildren().remove(0);
}
}
}
});
HBox hb = new HBox();
hb.getChildren().addAll(treeView,box2,box3,box4);
border.setCenter(hb);
}
private static class AddMenuTreeCell extends TextFieldTreeCell<String> {
private ContextMenu menu = new ContextMenu();
private TextField textField;
public AddMenuTreeCell() {
MenuItem newitem1 = new MenuItem("Insert leaf");
menu.getItems().add(newitem1);
newitem1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
TreeItem<String> newLeaf = new TreeItem<String>("UY" );
getTreeItem().getChildren().add(newLeaf);
}
});
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(getTreeItem().getGraphic());
if (!(getTreeItem().isLeaf() && getTreeItem().getParent() == null)){
setContextMenu(menu);
}
}
}
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
TextField textf1 = new TextField();
TextField textf2 = new TextField();
BorderPane root1 = new BorderPane();
private BorderPane getrightPane1() {
VBox vbox = new VBox(20);
vbox.setPadding(new Insets(10));
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
textf1.setPrefWidth(100);
textf1.setPromptText("Enter Height");
textf1.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf1.getText().length() > 0 && textf2.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setBottom(rect);
}
}
});
textf2.setPrefWidth(100);
textf2.setPromptText("Enter Width");
textf2.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf1.getText().length() > 0 && textf2.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setBottom(rect);
}
}
});
h1.getChildren().addAll(new Label("Y1:"), textf1);
h2.getChildren().addAll(new Label("X1:"), textf2);
vbox.getChildren().addAll(h1, h2);
root1.setLeft(vbox);
return root1;
}
TextField textf3 = new TextField();
TextField textf4 = new TextField();
BorderPane root2 = new BorderPane();
private BorderPane getrightPane2() {
VBox vbox = new VBox(20);
vbox.setPadding(new Insets(10));
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
textf3.setPrefWidth(100);
textf3.setPromptText("Enter Height");
textf3.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf3.getText().length() > 0 && textf4.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf3.getText()));
rect.setWidth(Double.parseDouble(textf4.getText()));
rect.setFill(null);
rect.setStroke(Color.BLUE);
root2.setBottom(rect);
}
}
});
textf4.setPrefWidth(100);
textf4.setPromptText("Enter Width");
textf4.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf3.getText().length() > 0 && textf4.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf3.getText()));
rect.setWidth(Double.parseDouble(textf4.getText()));
rect.setFill(null);
rect.setStroke(Color.BLUE);
root2.setBottom(rect);
}
}
});
h1.getChildren().addAll(new Label("Y2:"), textf3);
h2.getChildren().addAll(new Label("X2:"), textf4);
vbox.getChildren().addAll(h1, h2);
root2.setLeft(vbox);
return root2;
}
private HBox getrightPane3() {
HBox hbox = new HBox(20);
hbox.setAlignment(Pos.BOTTOM_CENTER);
hbox.setPadding(new Insets(50));
HBox hbox1 = new HBox();
Rectangle rect1 = new Rectangle();
if (!textf1.getText().equals("") && !textf2.getText().equals("")) {
rect1.setHeight(Double.parseDouble(textf1.getText()));
rect1.setWidth(Double.parseDouble(textf2.getText()));
rect1.setFill(null);
rect1.setStroke(Color.RED);
hbox1.getChildren().addAll(rect1);
}
HBox hbox2 = new HBox();
Rectangle rect2 = new Rectangle();
if (!textf3.getText().equals("") && !textf4.getText().equals("")) {
rect2.setHeight(Double.parseDouble(textf3.getText()));
rect2.setWidth(Double.parseDouble(textf4.getText()));
rect2.setFill(null);
rect2.setStroke(Color.BLUE);
hbox2.getChildren().addAll(rect2);
}
hbox.getChildren().addAll(hbox1,hbox2);
return hbox;
}
}
Root has 2 leafs Ux, Uy and both contains logic to build rectangle and that rectangles are Horizontally shown in root. Now the problem is that the user needs to add another leaf name Uy and that should have same Rectangle building logic and these newly build rectangles should be automatically shown in root.
I tried with adding another Uy but this doesn't work.
How can items be added to the tree?
I changed your code a little. The problem is that you are trying to add nodes to the scene more than once. In this example, I created a map that keeps up with the TreeView and the BorderPane associated with it.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.TextFieldTreeCell;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author blj0011
*/
public class JavaFXApplication124 extends Application
{
//List<BorderPane> rightPanels = new ArrayList();
static final Map<TreeItem<String>, BorderPane> MAP = new HashMap();
static BorderPane root;
#Override
public void start(Stage primaryStage)
{
TreeItem<String> treeRoot = new TreeItem("Main System");
root = new BorderPane();
TreeView treeView = new TreeView(treeRoot);
treeView.setOnMouseClicked((event)->{
TreeItem tempTreeItem = (TreeItem)treeView.getSelectionModel().getSelectedItem();
if(tempTreeItem.getValue().equals("Main System"))
{
root.setCenter(getRootsPanel());
//System.out.println(getRootsPanel());
}
else
{
root.setCenter(MAP.get(tempTreeItem));
System.out.println(MAP.get(tempTreeItem));
}
});
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new AddMenuTreeCell();
}
});
treeRoot.setExpanded(true);
root.setLeft(treeView);
TreeItem<String> uxItem1 = new TreeItem("UX");
MAP.put(uxItem1, getrightPane1());
TreeItem<String> uyItem1 = new TreeItem("UY");
MAP.put(uyItem1, getrightPane1());
treeRoot.getChildren().addAll(uxItem1, uyItem1);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
TreeItem<String> addNewTreeItem(String name)
{
TreeItem tempTreeItem = new TreeItem(name);
return tempTreeItem;
}
private static class AddMenuTreeCell extends TextFieldTreeCell<String> {
private final ContextMenu menu = new ContextMenu();
private TextField textField;
public AddMenuTreeCell() {
MenuItem newitem1 = new MenuItem("Insert leaf");
menu.getItems().add(newitem1);
newitem1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
TreeItem<String> newLeaf = new TreeItem("UY");
getTreeItem().getChildren().add(newLeaf);
MAP.put(newLeaf, getrightPane1());
}
});
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(item);
}
setText(null);
setGraphic(textField);
} else {
setText(item);
setGraphic(getTreeItem().getGraphic());
if (!(getTreeItem().isLeaf() && getTreeItem().getParent() == null)){
setContextMenu(menu);
}
}
}
}
}
private static BorderPane getrightPane1() {
TextField textf1 = new TextField();
TextField textf2 = new TextField();
BorderPane root1 = new BorderPane();
VBox vbox = new VBox(20);
vbox.setPadding(new Insets(10));
HBox h1 = new HBox(7);
HBox h2 = new HBox(7);
textf1.setPrefWidth(100);
textf1.setPromptText("Enter Height");
textf1.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf1.getText().length() > 0 && textf2.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setBottom(rect);
}
}
});
textf2.setPrefWidth(100);
textf2.setPromptText("Enter Width");
textf2.setOnKeyReleased(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event)
{
if(textf1.getText().length() > 0 && textf2.getText().length() > 0)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setBottom(rect);
}
}
});
if(textf1.getText().length() > 0 && textf2.getText().length() > 0 && root1.getBottom() == null)
{
Rectangle rect = new Rectangle();
rect.setHeight(Double.parseDouble(textf1.getText()));
rect.setWidth(Double.parseDouble(textf2.getText()));
rect.setFill(null);
rect.setStroke(Color.RED);
root1.setBottom(rect);
}
h1.getChildren().addAll(new Label("Y1:"), textf1);
h2.getChildren().addAll(new Label("X1:"), textf2);
vbox.getChildren().addAll(h1, h2);
root1.setLeft(vbox);
return root1;
}
private static BorderPane getRootsPanel() {
BorderPane root1 = new BorderPane();
HBox hbox = new HBox();
List<BorderPane> listBordePane = new ArrayList(MAP.values());
for(BorderPane element : listBordePane)
{
Node node = element.getBottom();
if(node instanceof Rectangle)
{
Rectangle tempRectangle = ((Rectangle)node);
Rectangle newRectangle = new Rectangle();
newRectangle.setWidth(tempRectangle.getWidth());
newRectangle.setHeight(tempRectangle.getHeight());
newRectangle.setFill(tempRectangle.getFill());
newRectangle.setStroke(tempRectangle.getStroke());
hbox.getChildren().add(newRectangle);
}
}
root1.setLeft(hbox);
return root1;
}
}
Code updated! You need to catch the TextField java.lang.NumberFormatException!

Display additional values in Pie chart

I have this example of Pie chart data:
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MainApp extends Application
{
Stage stage;
PieChart chart;
ObservableList<Data> pieChartData = FXCollections.observableArrayList();
Label caption;
#Override
public void start(Stage stage)
{
this.stage = stage;
setUserAgentStylesheet(STYLESHEET_CASPIAN);
Scene scene = new Scene(new Group());
stage.setTitle("Imported Fruits");
stage.setWidth(500);
stage.setHeight(500);
chart = new PieChart(pieChartData);
chart.setTitle("Imported Fruits");
// Add some data
addPieChartData("Grapefruit", 13);
addPieChartData("Oranges", 25);
addPieChartData("Plums", 10);
addPieChartData("Pears", 22);
addPieChartData("Apples", 30);
// Some task which updates the Pie Chart
final Task task;
task = new Task<Void>()
{
#Override
protected Void call() throws Exception
{
int max = 50;
int l = 0;
for (int i = 1; i <= max; i++)
{
updatePieChartData("Grapefruit", l++);
updatePieChartData("Oranges", l++);
Thread.sleep(600);
}
return null;
}
};
new Thread(task).start();
((Group) scene.getRoot()).getChildren().addAll(chart, caption);
stage.setScene(scene);
stage.show();
}
public void addPieChartData(String name, double value)
{
pieChartData.add(new Data(name, value));
caption = new Label();
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for (final Data data : chart.getData())
{
Node node = data.getNode();
node.addEventHandler(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent e)
{
caption.setTranslateX(e.getSceneX() + 15);
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(data.getPieValue()) + "%");
caption.setVisible(true);
node.setEffect(new Glow());
//String styleString = "-fx-border-color: white; -fx-border-width: 1; -fx-border-style: dashed;";
//node.setStyle(styleString);
}
});
node.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent e)
{
caption.setVisible(false);
node.setEffect(null);
//node.setStyle("");
}
});
final MenuItem resizeItem = new MenuItem("Resize");
resizeItem.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
System.out.println("Resize requested");
}
});
final MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
System.out.println("About requested");
}
});
final MenuItem changeColorItem = new MenuItem("Change Color");
changeColorItem.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
System.out.println("change Color Item requested");
}
});
final ContextMenu menu = new ContextMenu(resizeItem, aboutItem, changeColorItem);
node.setOnMouseClicked(new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
if (MouseButton.SECONDARY.equals(event.getButton()))
{
menu.show(stage, event.getScreenX(), event.getScreenY());
}
}
});
}
}
// updates existing Data-Object if name matches
public void updatePieChartData(String name, double value)
{
for (Data d : pieChartData)
{
if (d.getName().equals(name))
{
d.setPieValue(value);
return;
}
}
addPieChartData(name, value);
}
public static void main(String[] args)
{
launch(args);
}
}
Is there any way similar to tickLabelFormatter in Line chart to display additional values in Pie chart names?
I want to display each Pie slice with names and number.
Just bind the pie chart data name to the required value.
pieChartData.forEach(data ->
data.nameProperty().bind(
Bindings.concat(
data.getName(), " ", data.pieValueProperty(), " Tons"
)
)
);
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.chart.*;
import javafx.scene.Group;
public class PieChartSample extends Application {
#Override public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Imported Fruits");
stage.setWidth(500);
stage.setHeight(500);
ObservableList<PieChart.Data> pieChartData =
FXCollections.observableArrayList(
new PieChart.Data("Grapefruit", 13),
new PieChart.Data("Oranges", 25),
new PieChart.Data("Plums", 10),
new PieChart.Data("Pears", 22),
new PieChart.Data("Apples", 30));
final PieChart chart = new PieChart(pieChartData);
chart.setTitle("Imported Fruits");
pieChartData.forEach(data ->
data.nameProperty().bind(
Bindings.concat(
data.getName(), " ", data.pieValueProperty(), " Tons"
)
)
);
((Group) scene.getRoot()).getChildren().add(chart);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you have changing values (like in the example code) and/or want to avoid displaying the values in the chart legend, you could modify the text label instead of changing the data names.
Each data item has a text node that holds the string which is shown as the pie chart label. This string can be updated before the chart children are drawn by overriding PieChart#layoutChartChildren:
chart = new PieChart(pieChartData) {
#Override
protected void layoutChartChildren(double top, double left, double contentWidth, double contentHeight) {
if (getLabelsVisible()) {
getData().forEach(d -> {
Optional<Node> opTextNode = chart.lookupAll(".chart-pie-label").stream().filter(n -> n instanceof Text && ((Text) n).getText().contains(d.getName())).findAny();
if (opTextNode.isPresent()) {
((Text) opTextNode.get()).setText(d.getName() + " " + d.getPieValue() + " Tons");
}
});
}
super.layoutChartChildren(top, left, contentWidth, contentHeight);
}
};

Resources