JavaFX - Separate Child Bounding Box from Parent - javafx

I am having an issue with a graph I have made in JavaFX. I am creating a label and adding it to a point on mouse enter:
Label label = new Label(s);
label.setTranslateY(-20.0);
...
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
toFront();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
}
});
This ends up with the point and the label sharing a bounding box.
I would like the bounding boxes of the two to be separate. This way, when the cursor exits the point, the label should disappear. Currently, the label will still display as long as it is in the box generated by the label and point combined.
I would appreciate any help on figuring out how to separate the bounding boxes of these two elements.
Thanks!

To solve this, I ended up creating a new empty node which sits at the top middle of the graph. When a point is hovered, the label is added to the newly created node. This allows the user to hover the points without the label getting in the way.

Related

How to draw a line in JavaFX with the mouse?

I am working on a paint program in which a button is clicked that toggles the button that draws lines. My code doesn't do what I want it to and instead draws a strange fan shape whenever I try to draw multiple lines. I want it to be able to draw multiple straight lines with the mouse.
canvas.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
initialTouch = new Pair<>(event.getX(), event.getY());
}
});
canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
gc.strokeLine(initialTouch.getKey(), initialTouch.getValue(), event.getX(), event.getY());
}
});
canvas.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
}
});
}```
That method is called when a button is pushed to draw the line. I am expecting multiple lines, but I stead get a fan shape.
What you do, is:
You create start Point.
And then for each DRAG movement you create a OWN line from the Start location to the new Location. Hence you create a lot of lines that resemble a shape.
What you want is:
Create a start point and than draw to the end Point.
So you should ONLY draw a line to the Graphical Context when the Mouse released.
just Move what you do in "dragged" to the "released" part and it sould work.
When you want "Preview" you should Use a Line Object and add it to the View, and then when release the mouse you should delete the Object it.

How to put multiple TextField in a circle in JavaFx

I am trying to put multiple textfields in a circle in JavaFX. I could add a field in the centre using StackPane as explained in the below-mentioned post but unable to add multiple textfields. I tried using different panes for that but it didn't work.
Added the code that doesn't work.I want to add two text fields at any place inside a circle. Using gridpane for it didn't work. Moreover, I want to create x number of circle dynamically at any place in a gridpane and add multiple text fields to the circle, is it possible to do that using JavaFX?
Hope I am able to explain the problem statement correctly. Any response is appreciated :)
#Override
public void start(Stage arg0) throws Exception {
arg0.setTitle("Text Boxes In circle");
arg0.setMaxWidth(500);
Circle circle = createCircle(); // This function is to form a circle.
Text text = new Text("42");
Text text1 = new Text("36");
text.setBoundsType(TextBoundsType.VISUAL);
text1.setBoundsType(TextBoundsType.VISUAL);
GridPane box = new GridPane();
// box.setConstraints(text, 2, 0); commented this out to check if it was not
// causing problem but still didn't work
// box.setConstraints(text1, 2, 1);
// box.setAlignment(Pos.CENTER); Even used this to center the gridPane didn't
// work either.
StackPane stack = new StackPane();
box.getChildren().addAll(text, text1);
stack.getChildren().addAll(box, circle);
Scene scene = new Scene(stack);
arg0.setScene(scene);
arg0.show();
}
public static void main(String[] args) {
launch(args);
}
private static Circle createCircle() {
final Circle circle = new Circle(100);
circle.setStroke(Color.FORESTGREEN);
circle.setStrokeWidth(10);
circle.setStrokeType(StrokeType.INSIDE);
circle.setFill(Color.AZURE);
return circle;
}
how to put a text into a circle object to display it from circle's center?

Javafx retrievable drag and drop bug

I am creating a javafx application with a drag and drop feature. I need to be able to drag from one pane and drop to the next pane. After dropping, all dropped nodes need to be accessible. The drag and drop is working smoothly. However, I am having a problem in which not all nodes are accessible after being dropped. I would drag a node and click on it and sometimes it would respond, but sometimes a random node would no longer exhibit capabilities when I clicked on it. There was no noticeable pattern (that I could see) about which nodes stopped working and which always worked. If anyone has any idea as to why this might be a problem or how to fix it, it would be greatly appreciated. I have looked everywhere and found only one similar issue a few years ago but the page with their solution had been removed.
I will briefly explain how I set up my code structure.
The nodes I am dragging extend StackPane and I drag these nodes onto a center Pane from an ImageView in VBox. However, both of these are children of a Main layout that extends BorderPane which I have called MainEntrance.
In my node's class I have onMousePressed and onMouseDragged features as well as onContextMenuRequested features. In the class of the MainEntrance, I have drag features, as well, that handle when an object is first dragged onto the child Pane from the other child VBox.
The following are the relevant classes/methods:
VBox class: (where nodes are dragged from)
ImageView iV= new ImageView(image);
iV.setId("image");
iV.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
dragAndDrop(iV, iV.getId(), event);
}
});
I have drag three ImageViews and these ImageViews are children of a VBox.
MainEntrance:
In this class I have a method that registers my drag events to my pane as such:
PView is my class extension of Pane
public void registerOnDragDropped(PView pView){
pView.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
event.acceptTransferModes(TransferMode.ANY);
System.out.println("drag over registered");
}
});
pView.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
final String id = db.getString();
double mousePosY = event.getY();
double mousePosX = event.getX();
deviceCounter += 1;
pView.createBoardView(id, deviceCounter, mousePosX, mousePosY);
event.setDropCompleted(true);
}
});
pView.setOnDragExited(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
event.acceptTransferModes(TransferMode.ANY);
//computerView.setEffect(null);
event.consume();
}
});
}
Note: this method is in my MainEntrance class (BorderPane). In this class is when I initialize all other child nodes of MainEntrance.
Node: (draggable nodes extend StackPane)
my node's handlers are in a method that I called makeDraggable()
public void makeDraggable(Node node) {
this.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
node.getScene().setCursor(Cursor.MOVE);
System.out.println("makeDraggable mouse pressed");
}
});
node.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
node.getScene().setCursor(Cursor.DEFAULT);
}
});
node.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
node.setTranslateX(node.getTranslateX() + event.getX() - 35);
node.setTranslateY(node.getTranslateY() + event.getY() - 35);
event.consume();
node.toFront();
}
});
}
If any other information is needed please let me know. Thank you in advance!
I have figured out the solution to this problem.
The problem was in the rendering order of an attachment I had placed on the node. So when I drag the node on to the screen, I have another node (a line placed on a Pane) that binds the center of the screen to the node. I did not initially think that this was the problem, so I did not even include that class or snippet. However, after playing around with it I realized that this indeed was the problem. I had to add the line to the top of the rendering order. This can be done in the following way in whatever method allows you to create a new node:
Pane line = new Pane();
//add whatever code binds your line to desired places
getChildren.add(0, line);
//add the other node as child

Make a BorderPane region go over another

I've been trying for days and days now to get a BorderPane region go over another region...
The problem is as follow: My app is set in a BorderPane root, With:
A header in its TOP region
A menu in its LEFT region
The content, depending on the page, in it's CENTER
And an optional panel on its RIGHT region
That right region is the problem. It should appear/disappear when clicking on a "notification button" that is in the TOP region. So far so good. The thing is that the app doesn't use the RIGHT region, so I'm trying to make the RIGHT region that contains an AnchorPane go over the CENTER region. The normal state of the app is without the RIGHT region and I don't want to resize the whole app when opening the noitifications. Tried several things, such as:
When clicking the notification button, send the CENTER part toBack() and set the RIGHT width to the 300 wanted pixels
Sending the RIGHT region toFront()
Sending the whole BorderPane toFront()
None of them work, as they all either not show, or resize the center part which I don't want. I'd like the RIGHT to float above the CENTER region when the notification menu is showing.... Is there any way to do that? Or maybe another idea to trigger a container that would show above the CENTER part? Of course, I go design the panel in every CENTER pane and make it visible or not, but my app is about 15 different center windows so it would be really bad in terms of modifications...
I think you should not be trying to make the borderpane do this for you or you will end up with behavior you do not want like the center NOT resizing when the application is resized while the panel is visible.
Remember that JavaFX is really 3D. How about you try to wrap the BorderPane inside of an AnchorPane, GridPane or ScrollPane (whichever makes sense) instead of trying to get the right insert to do your thing. e.g. add an ScrollPane (your Slider) to the containing AnchorPane and bring that to the front and anchor it's top, right and bottom.
This should give you a right-aligned ScrollPane on top of your borderpane.
Then of course if you want it to be fancy with an animated slide you can try this out : https://gist.github.com/jewelsea/1437374
or this:
http://blog.physalix.com/javafx2-borderpane-which-slides-in-and-out-on-command/
Here is a very rough example to show the idea:
public class JavaFXApplication2 extends Application {
ScrollPane slider;
AnchorPane root;
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Slide in");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().add(slider);
AnchorPane.setRightAnchor(slider, 0.);
AnchorPane.setTopAnchor(slider, 0.);
AnchorPane.setBottomAnchor(slider, 0.);
slider.toFront();
}
});
Label l = new Label();
l.setText("Test Label to Show inside content");
Label l2 = new Label();
l2.setText("Peek-a-Boo");
slider = new ScrollPane();
slider.setStyle("-fx-border-color: orangered;");
slider.setContent(l2);
root = new AnchorPane();
root.getChildren().add(btn);
root.getChildren().add(l);
AnchorPane.setRightAnchor(l, 0.);
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);
}
}

How to resize WorldWind Panel?

I want to put a WorldWindowGLJPanel into a Pane, and I want to make it resizable, but I can't, even when I call resize or setSize method.
Here's what I'm doing :
wwd = new WorldWindowGLJPanel();
wwd.setPreferredSize(new java.awt.Dimension(300, 300));
wwd.setModel(new BasicModel());
swingNode = new SwingNode();
swingNode.setContent(wwd);
wwdPane = new Pane();
wwdPane.getChildren().add(swingNode);
Then I use this wwdPane to display World Wind.
I want my world wind panel to have the size of the pane which contains it, and I want to make this world wind panel resizable.
I thought about give the size to my world wind panel of my pane with a setSize(PaneDimenson) and then bind the size of my worldwindpanel with my pane , but the setSize function doesn't work.
EDIT : I found an alternative solution by not using a pane, but directly the swingNode, the resize is now automatic. But if you want to use a pane there's still a problem, and you're force to use a group.
The setSize is working, try this code:
scene.widthProperty().addListener(new ChangeListener<Number>() {
#Override public void changed( ObservableValue<? extends Number> o, Number b, Number a ) {
Platform.runLater(new Runnable() {
public void run() {
wwd.setSize((int)(a.intValue()*0.5), wwd.getHeight());
}
});
or with Java8
scene.widthProperty().addListener((o,b,a)->Platform.runLater(()->
wwd.setSize((int)(a.intValue()*0.5), wwd.getHeight())));
But I couldn't make the resize work in my sample code, because the SwingNode somehow mess up the resizing, I think you should try the solution advised here.

Resources