JavaFX Circle object not registering mouse events properly - javafx

I want the user to be able to drag-move the circles around the pane. The circles dont seem to register (almost) no mouse events (as defined in the end). I have the same exact code for an empty pane it works just fine. Also if I change
circle1.setOnMouseDragged
to
paneForCircles.setOnMouseDragged
it works just fine but its not what I want because I need to manipulate both circles. Any ideas ? I would appreciate it if you could also tell me how to hide the part of the circle that overlaps with the adjacent elements if its center is too close to the pane border.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Ex168 extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Circle circle1 = new Circle(30);
Circle circle2 = new Circle(35);
circle1.setCenterX(100);
circle1.setCenterY(100);
circle2.setCenterX(150);
circle2.setCenterY(120);
circle1.setStroke(Color.BLACK);
circle1.setFill(null);
circle2.setStroke(Color.BLACK);
circle2.setFill(null);
VBox vBoxForScene = new VBox(5);
vBoxForScene.setPadding(new Insets(5));
vBoxForScene.setAlignment(Pos.TOP_CENTER);
Pane paneForCircles = new Pane();
paneForCircles.setStyle("-fx-border-color: black");
vBoxForScene.heightProperty().addListener(ov -> paneForCircles.setPrefHeight(vBoxForScene.heightProperty().divide(1.2).doubleValue()));
paneForCircles.setPrefHeight(300);
HBox hBoxForFields = new HBox(5);
hBoxForFields.setAlignment(Pos.CENTER);
hBoxForFields.setSpacing(5);
// VBofForLeftFields
VBox vBoxForLeftFields = new VBox(5);
vBoxForLeftFields.setAlignment(Pos.CENTER_LEFT);
Label lblCircle1 = new Label("Enter Circle 1 info");
lblCircle1.setAlignment(Pos.TOP_LEFT);
TextField tfCircle1CenterX = new TextField();
tfCircle1CenterX.textProperty().bind(circle1.centerXProperty().asString());
TextField tfCircle1CenterY = new TextField();
tfCircle1CenterY.textProperty().bind(circle1.centerYProperty().asString());
TextField tfCircle1Radius = new TextField();
tfCircle1Radius.textProperty().bind(circle1.radiusProperty().asString());
tfCircle1CenterX.setPrefColumnCount(5);
tfCircle1Radius.setPrefColumnCount(5);
tfCircle1CenterY.setPrefColumnCount(5);
Label lblCenterX = new Label("Center x:", tfCircle1CenterX);
Label lblCenterY = new Label("Center x:", tfCircle1CenterY);
Label lblCircle1Radius= new Label("Radius: ", tfCircle1Radius);
lblCenterX.setContentDisplay(ContentDisplay.RIGHT);
lblCenterY.setContentDisplay(ContentDisplay.RIGHT);
lblCircle1Radius.setContentDisplay(ContentDisplay.RIGHT);
//VBoxForRightFields
VBox vBoxForRightFields = new VBox(5);
Label lblCircle2 = new Label("Enter Circle 2 info");
TextField tfCircle2CenterX = new TextField();
TextField tfCircle2CenterY = new TextField();
TextField tfCircle2Radius = new TextField();
tfCircle2CenterX.setPrefColumnCount(5);
tfCircle2CenterX.textProperty().bind(circle2.centerXProperty().asString());
tfCircle2Radius.setPrefColumnCount(5);
tfCircle2Radius.textProperty().bind(circle2.radiusProperty().asString());
tfCircle2CenterY.setPrefColumnCount(5);
tfCircle2CenterY.textProperty().bind(circle2.centerYProperty().asString());
Label lblCenter2X = new Label("Center x:", tfCircle2CenterX);
Label lblCenter2Y = new Label("Center x:", tfCircle2CenterY);
Label lblCircle2Radius= new Label("Radius: ", tfCircle2Radius);
lblCenter2X.setContentDisplay(ContentDisplay.RIGHT);
lblCenter2Y.setContentDisplay(ContentDisplay.RIGHT);
lblCircle2Radius.setContentDisplay(ContentDisplay.RIGHT);
vBoxForRightFields.getChildren().addAll(lblCircle2, lblCenter2X, lblCenter2Y, lblCircle2Radius);
vBoxForLeftFields.getChildren().addAll(lblCircle1, lblCenterX, lblCenterY, lblCircle1Radius);
hBoxForFields.getChildren().addAll(vBoxForLeftFields, vBoxForRightFields);
Label lblResult = new Label("Do the two circles intersect?");
Button btReDrawCircles = new Button("Redraw Circles");
vBoxForScene.getChildren().addAll(lblResult, paneForCircles, hBoxForFields, btReDrawCircles);
circle1.setOnMouseDragged(e -> {
System.out.println(e.getX());
circle1.setCenterX(e.getX());
circle1.setCenterY(e.getY());
});
circle2.setOnMouseDragged(e -> {
circle2.setCenterX(e.getX());
circle2.setCenterY(e.getY());
});
paneForCircles.getChildren().addAll(circle1, circle2);
Scene scene = new Scene(vBoxForScene);
primaryStage.setScene(scene);
primaryStage.setMinHeight(400);
primaryStage.setMinWidth(340);
primaryStage.setAlwaysOnTop(true);
primaryStage.show();
circle1.requestFocus();
}
}
This code on the other hand, which is supposed to do the same thing, works perfectly
public class CircleDraggingSample extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
final double RADIUS=10;
Pane pane = new Pane();
pane.setPrefHeight(300);
pane.setPrefWidth(300);
Circle circle1 = new Circle(RADIUS);
circle1.setCenterX(30);
circle1.setCenterY(30);
Circle circle2 = new Circle(RADIUS);
circle2.setCenterX(100);
circle2.setCenterY(100);
Line line = new Line();
line.endXProperty().bind(circle2.centerXProperty());
line.endYProperty().bind(circle2.centerYProperty());
line.startXProperty().bind(circle1.centerXProperty());
line.startYProperty().bind(circle1.centerYProperty());
pane.getChildren().addAll(circle1, circle2, line);
circle2.setOnMouseDragged(e -> {
circle2.setCenterX(e.getX());
circle2.setCenterY(e.getY());
});
circle1.setOnMouseDragged(e -> {
circle1.setCenterX(e.getX());
circle1.setCenterY(e.getY());
});
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
}

Even though you have posted an example, I'd rather show you a way with mine how it is done in general. There are several ways, this is one that works:
public class DragNodes extends Application {
public static List<Circle> circles = new ArrayList<Circle>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Circle circle1 = new Circle( 100, 100, 50);
circle1.setStroke(Color.GREEN);
circle1.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.3));
Circle circle2 = new Circle( 200, 200, 50);
circle2.setStroke(Color.BLUE);
circle2.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.3));
Line line = new Line();
line.setStrokeWidth(20);
// binding
line.startXProperty().bind(circle1.centerXProperty());
line.startYProperty().bind(circle1.centerYProperty());
line.endXProperty().bind(circle2.centerXProperty());
line.endYProperty().bind(circle2.centerYProperty());
MouseGestures mg = new MouseGestures();
mg.makeDraggable( circle1);
mg.makeDraggable( circle2);
mg.makeDraggable( line);
root.getChildren().addAll(circle1, circle2, line);
primaryStage.setScene(new Scene(root, 1024, 768));
primaryStage.show();
}
public static class MouseGestures {
class DragContext {
double x;
double y;
}
DragContext dragContext = new DragContext();
public void makeDraggable( Node node) {
node.setOnMousePressed( onMousePressedEventHandler);
node.setOnMouseDragged( onMouseDraggedEventHandler);
node.setOnMouseReleased(onMouseReleasedEventHandler);
}
EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if( event.getSource() instanceof Circle) {
Circle circle = ((Circle) (event.getSource()));
dragContext.x = circle.getCenterX() - event.getSceneX();
dragContext.y = circle.getCenterY() - event.getSceneY();
} else {
Node node = ((Node) (event.getSource()));
dragContext.x = node.getTranslateX() - event.getSceneX();
dragContext.y = node.getTranslateY() - event.getSceneY();
}
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if( event.getSource() instanceof Circle) {
Circle circle = ((Circle) (event.getSource()));
circle.setCenterX( dragContext.x + event.getSceneX());
circle.setCenterY( dragContext.y + event.getSceneY());
} else {
Node node = ((Node) (event.getSource()));
node.setTranslateX( dragContext.x + event.getSceneX());
node.setTranslateY( dragContext.y + event.getSceneY());
}
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
}
};
}
}
It shows how to drag circles and bind another node (the line) so that it gets modified as well when you drag the circles. You can also drag the line separately which is a Node and handled differently.
In case you still got problems let me know.
As a general note, it's always advisable to add this to a node in order to understand which events happen:
node.addEventFilter(Event.ANY, e -> System.out.println( e));
and then check the console output while you do something on screen.
Regarding your main problem: You mustn't set Fill to null. In that case the click event won't get registered. You should use Color.TRANSPARENT instead. You can verify the event difference with the above mentioned method.

Related

JavaFx canvas mouse events

I would like to intercept mouse events on canvas only where I've drawn some shape, but in all other transparent area I would like to have behaviour like with property mouseTransparent true.
I can achieve that with ImageView, transparent areas doesn't intercept mouse events.
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Drawing Operations Test");
Pane root = new Pane();
root.setStyle("-fx-background-color: #C9E3AF");
root.setMinSize(1000, 1000);
root.setOnMouseClicked(event -> {
System.out.println("Clicked on root pane");
});
Canvas canvas1 = new Canvas(512, 512);
canvas1.getGraphicsContext2D().setFill(Color.BLACK);
canvas1.getGraphicsContext2D().fillRect(250, 250, 250, 250);
canvas1.setOnMouseClicked(event -> {
System.out.println("Clicked on canvas1");
});
canvas1.setPickOnBounds(false);
Canvas canvas2 = new Canvas(512, 512);
canvas2.getGraphicsContext2D().setFill(Color.RED);
canvas2.getGraphicsContext2D().fillRect(200, 200, 250, 250);
canvas2.setOnMouseClicked(event -> {
System.out.println("Clicked on canvas2");
});
canvas2.setPickOnBounds(false);
SnapshotParameters param1 = new SnapshotParameters();
param1.setFill(Color.TRANSPARENT);
WritableImage image1 = canvas1.snapshot(param1, new WritableImage(512, 512));
SnapshotParameters param2 = new SnapshotParameters();
param2.setFill(Color.TRANSPARENT);
WritableImage image2 = canvas2.snapshot(param2, new WritableImage(512, 512));
ImageView view1 = new ImageView(image1);
view1.setOnMouseClicked(event -> {
System.out.println("Clicked on view1");
});
view1.setPickOnBounds(false);
ImageView view2 = new ImageView(image2);
view2.setOnMouseClicked(event -> {
System.out.println("Clicked on view2");
});
view2.setPickOnBounds(false);
// ImageView test
// root.getChildren().addAll(view1, view2);
// Canvas test
root.getChildren().addAll(canvas1, canvas2);
Scene sc = new Scene(root);
primaryStage.setScene(sc);
primaryStage.setX(0);
primaryStage.setY(0);
primaryStage.show();
}
Is it even possible with Canvas?
As far as I'm concerned it is impossible to achieve using Canvas, but using Group and Shapes within gives you all the features of Canvas plus behaviour you expect.
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ShapesApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Circle circle = new Circle(100);
circle.setFill(Color.BLUE);
Group group = new Group(circle);
group.setOnMouseMoved(System.out::println);
StackPane stackPane = new StackPane(group);
stackPane.setPrefSize(400, 400);
stage.setScene(new Scene(stackPane));
stage.show();
}
}

Draw Arrows over Nodes

I want to draw arrows in a group over my grid view. The example works fine with 3x3 grid. But if I change this size to e.g. 4x4 these arrows are on the wrong place.
I colorized the source field (green) and the destination field (red) to make sure I target the right cells. The program clears the arrowGroup and draws two arrows every 3s.
import eu.lestard.grid.GridModel;
import eu.lestard.grid.GridView;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import static javafx.scene.paint.Color.RED;
public class App extends Application {
private GridView<States> gridView;
private StackPane stackPane;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane borderPane = new BorderPane();
stackPane = new StackPane();
borderPane.setCenter(stackPane);
Group arrowGroup = new Group();
GridModel<States> gridModel = new GridModel<>();
gridModel.setDefaultState(States.EMPTY);
gridModel.setNumberOfColumns(3);
gridModel.setNumberOfRows(3);
gridView = new GridView<>();
gridView.setGridModel(gridModel);
stackPane.getChildren().add(gridView);
stackPane.getChildren().add(arrowGroup);
final Scene scene = new Scene(borderPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
new Thread(() -> {
for (int i = 1; i <= 1000000; i++) {
Platform.runLater( () -> {
arrowGroup.getChildren().clear();
drawArrow(arrowGroup, new Point2D(0,0), new Point2D(2,1));
drawArrow(arrowGroup, new Point2D(1,1), new Point2D(0,2));
});
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
}).start();
}
// getRelativeBounds, getCenter based on https://stackoverflow.com/a/43119383/772883
private void drawArrow(Group group, Point2D from, Point2D to) {
final Line line = new Line();
System.out.println(String.format("Draw arrow from cell %s to %s", from, to));
System.out.println(String.format("group coord %s %s", group.getLayoutX(), group.getLayoutY()));
// Note: (X,Y) -> (Column, Row) => access via (Y,X)
final Pane cellPane = gridView.getCellPane(gridView.getGridModel().getCell(((int) from.getY()), (int) from.getX() ));
final Pane cellPane2 = gridView.getCellPane(gridView.getGridModel().getCell((int) to.getY() , (int) to.getX()));
cellPane.setBackground(new Background(new BackgroundFill(Color.DARKGREEN, CornerRadii.EMPTY, Insets.EMPTY)));
cellPane2.setBackground(new Background(new BackgroundFill(RED, CornerRadii.EMPTY, Insets.EMPTY)));
Bounds n1InCommonAncestor = getRelativeBounds(cellPane, gridView);
Bounds n2InCommonAncestor = getRelativeBounds(cellPane2, gridView);
Point2D n1Center = getCenter(n1InCommonAncestor);
Point2D n2Center = getCenter(n2InCommonAncestor);
System.out.println(String.format("Draw arrow from coord %s to %s", n1Center, n2Center));
System.out.println(n1Center);
System.out.println(n2Center);
line.setStartX(n1Center.getX());
line.setStartY(n1Center.getY());
line.setEndX(n2Center.getX());
line.setEndY(n2Center.getY());
group.getChildren().add(line);
}
private Bounds getRelativeBounds(Node node, Node relativeTo) {
Bounds nodeBoundsInScene = node.localToScene(node.getBoundsInLocal());
return relativeTo.sceneToLocal(nodeBoundsInScene);
}
private Point2D getCenter(Bounds b) {
return new Point2D(b.getMinX() + b.getWidth() / 2, b.getMinY() + b.getHeight() / 2);
}
public static enum States {
EMPTY,
X,
O
}
}
(If have replaced the arrows with lines to reduce the code.)
There is a gist withe the code and a gradle buildfile:
https://gist.github.com/anonymous/c54b12ee04b7e45f2e9f58e9de1d1df0
It would be great if somebody could explain why does only work with 3x3. Is there any better option than a group?

Adding multiple nodes to vbox javafx

I am new in JavaFx and I spend too much time trying to put radio button + textfield dynamically. After typing a number, I want to display my radio buttons and my TextFields in that way (blue and red ones)
But I got this:
I tried with vbox, hbox, both of them, but it did not work!
Can anyone figure out the problem in my code please!!! Thanks for your help
RadioButton[] btn = new RadioButton[100]; //our Collection to hold newly created Buttons
TextField[] xlist = new TextField[100]; //our Collection to hold newly created Buttons
TextField[] ylist = new TextField[100];
final ToggleGroup grpBtn = new ToggleGroup();
#FXML
private Group noeuds;
#FXML
private VBox vb2;
#FXML
private HBox hb2;
#FXML
public void addBtn(int i, RadioButton[] btn) {
btn[i] = new RadioButton();
btn[i].setText(String.valueOf(i + 1));
btn[i].setToggleGroup(grpBtn);
btn[i].setSelected(true);
btn[i].setTranslateX(-5);
btn[i].setTranslateY(-340);
btn[i].setPadding(new Insets(0, 0, 20, 20));
vb2.getChildren().add(btn[i]);
}
#FXML
public void addX(int i, TextField[] xlist) {
xlist[i] = new TextField();
xlist[i].setTranslateX(-80);
xlist[i].setTranslateY(40);
xlist[i].setStyle("-fx-background-color: red;");
xlist[i].setPrefSize(30, 30);
xlist[i].setTooltip(new Tooltip("X coordinate of " + (i + 1)));
hb2.getChildren().add(xlist[i]);
}
#FXML
public void addY(int i, TextField[] ylist) {
ylist[i] = new TextField();
ylist[i].setTranslateX(-78);
ylist[i].setTranslateY(40);
ylist[i].setStyle("-fx-background-color: blue;");
ylist[i].setPrefSize(30, 30);
ylist[i].setTooltip(new Tooltip("Y coordinate of" + (i + 1)));
hb2.getChildren().add(ylist[i]);
}
public void initialize(URL url, ResourceBundle rb) {
//some code
for (int i = 0; i < Integer.parseInt(nodeID.getText()); i++) {
addBtn(i, btn);
// System.out.println("jjjj"+btn.length);
addX(i, xlist);
// System.out.println("mmmm"+xlist.length);
addY(i, ylist);
}
}
This little app might help give you a boost. Read over the code and try to get an understanding. I tried to make comments in the code.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication7 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
VBox vbox1 = new VBox();
vbox1.setSpacing(5);//Set vbox spacing
//Handles the number of row to be added to the vbox
for(int i = 0; i < 4; i++)
{
vbox1.getChildren().add(addNewRow(i));
}
root.getChildren().add(vbox1);
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);
}
//Method creates all the nodes for a new row.
HBox addNewRow(int rowNumber)
{
//Create nodes and adding correct spaceing
HBox hbox = new HBox();
hbox.setSpacing(5);
RadioButton radioButton = new RadioButton();
radioButton.setPrefHeight(25);
TextField textField = new TextField();
textField.setPrefWidth(40);
Label label = new Label(Integer.toString(rowNumber + 1));
label.setPrefHeight(25);
HBox trailingHBox = new HBox();
trailingHBox.setSpacing(5);
hbox.getChildren().addAll(radioButton, textField, label, trailingHBox);
//Event handler on textfield. Add right about of trailing textfields
textField.setOnKeyReleased((event)->{
if(textField.getText().trim().length() > 0 && Integer.parseInt(textField.getText()) > 0)//If textfield has some value greater than zero. I didn't catch for non integers
{
int tempInt = Integer.parseInt(textField.getText());
//clear trailingHBox so that new Trailing hbox can be added
if(trailingHBox.getChildren().size() > 0)
{
trailingHBox.getChildren().clear();
}
//add the correct number of textFields.
for(int i = 0; i < tempInt - 1; i++)
{
TextField tempTextField = new TextField();
tempTextField.setPrefWidth(20);
trailingHBox.getChildren().add(tempTextField);
}
//add the blue and red textfields
TextField textFieldBlue = new TextField();
textFieldBlue.setPrefWidth(40);
textFieldBlue.setStyle("-fx-background-color: BLUE");
TextField textFieldRed = new TextField();
textFieldRed.setPrefWidth(40);
textFieldRed.setStyle("-fx-background-color: RED");
trailingHBox.getChildren().addAll(textFieldBlue, textFieldRed);
}
else{
trailingHBox.getChildren().clear();//clear traingHbox if it's has no value
}
});
return hbox;
}
}

change value in combobox ["example"] to "example" in javafx

i am using a combobox to get data from the database on stage.show(), so far i can retrieve the data and also implement my changelistener on the combobox.
the problem is that i am getting ["example"] from the database instead of "example". its my first time of using javafx and don;t know how the output is supposed to look like, but this one is strange to me.
below is a screenshot of it and also my code
[http://i.stack.imgur.com/QWawZ.png]
package libman;
import java.sql.*;
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.*;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.stage.*;
import javafx.scene.control.*;
import javafx.scene.text.*;
import javafx.collections.*;
/**
/**
*
* #author kels
*/
public class BorrowMenu extends Application {
private ObservableList<ObservableList> data;
DBOperator login;
ResultSet rs;
Statement stat;
private String getval;
#Override
#SuppressWarnings({"static-access", "Convert2Lambda"})
public void start(Stage primaryStage){
//define the UI elements
Label lblID = new Label("Name: ");
Label lblTitle = new Label("Book Title: ");
Label lblauthor = new Label("Author: ");
Label lblissue = new Label("Issue Date: ");
Label lblreturn = new Label("Return Date: ");
ComboBox title = new ComboBox();
TextField txtid = new TextField();
TextField txtitle = new TextField();
TextField txtauthor = new TextField();
TextField txtissue = new TextField();
TextField txtreturn = new TextField();
//set prompt text
txtid.setPromptText("Enter Borrower's Name");
txtitle.setPromptText("Enter Book Title");
txtauthor.setPromptText("Enter Author's Name");
txtissue.setPromptText("Enter Issue Date");
txtreturn.setPromptText("Enter Return Date");
title.setPromptText("Fills books from database");
//ToolTip ttip = new ToolTip("Back Menu");
Button btn = new Button("Borrow Book");
Button btnexit = new Button("Menu>>");
btnexit.setTooltip(new Tooltip("Back to Menu"));
//set the gripane to add in components
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(20));
gridpane.setHgap(5);
gridpane.setVgap(5);
//set components
gridpane.setHalignment(lblID, HPos.RIGHT);
gridpane.add(lblID, 0,0);
gridpane.setHalignment(txtid, HPos.RIGHT);
gridpane.add(txtid,1,0);
gridpane.setHalignment(lblTitle, HPos.RIGHT);
gridpane.add(lblTitle, 0,1);
gridpane.setHalignment(title, HPos.RIGHT);
gridpane.add(title, 1,1);
gridpane.setHalignment(lblauthor, HPos.RIGHT);
gridpane.add(lblauthor, 0,2);
gridpane.setHalignment(txtauthor, HPos.RIGHT);
gridpane.add(txtauthor, 1,2);
gridpane.setHalignment(lblissue, HPos.RIGHT);
gridpane.add(lblissue, 0,3);
gridpane.setHalignment(txtissue, HPos.RIGHT);
gridpane.add(txtissue, 1,3);
gridpane.setHalignment(lblreturn, HPos.RIGHT);
gridpane.add(lblreturn, 0,4);
gridpane.setHalignment(txtreturn, HPos.RIGHT);
gridpane.add(txtreturn, 1,4);
gridpane.setHalignment(btn, HPos.RIGHT);
gridpane.add(btn, 1,5);
gridpane.setHalignment(btnexit, HPos.RIGHT);
gridpane.add(btnexit, 2,5);
//display the values from db to combobox on windows launch
data = FXCollections.observableArrayList();
primaryStage.setOnShowing(new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent event){
try{
login = new DBOperator();
stat = login.getStatement();
rs=stat.executeQuery("SELECT * FROM BOOKDB");
while(rs.next()){
ObservableList<String> row =FXCollections.observableArrayList();
row.add(rs.getString("Title"));
// row.add(rs.getString("Author"));
data.add(row);
}
title.setItems(data);
rs.close();
}
catch(SQLException ex){
System.out.println("Driver Not Found!!!" + ex);
System.exit(0);
}
}
});
//add the gridpane to the stackpane
StackPane root = new StackPane();
root.getChildren().add(gridpane);
//title.setO
Scene scene = new Scene(root, 380,220);
primaryStage.setTitle("Borrow Menu");
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
//System.out.println(row);
//activate the combo listener at selection
title.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>(){
#Override
public void changed(ObservableValue<? extends Object> observable, Object oldvalue, Object newvalue){
System.out.println(newvalue.toString());
// txtauthor.setText(newvalue.toString());
}
});
}
public static void main(String [] args){
launch(args);
}
}
Please help thanks
You are getting the correct result for what you are actually doing: ObservableList<ObservableList> data bundles two collections.
For each item of the comboBox you will have a collection, so that's why you see "[ ]" when it is rendered.
This minimum sample reproduces your case:
#Override
public void start(Stage primaryStage) {
ComboBox title = new ComboBox();
StackPane root = new StackPane();
root.getChildren().add(title);
ObservableList<ObservableList> data = FXCollections.observableArrayList();
List<String> test = Arrays.asList("Test", "Example");
for(String s : test) {
ObservableList<String> row =FXCollections.observableArrayList();
row.add(s);
data.add(row);
}
title.setItems(data);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
with the same result you have:
You need to simplify your collection: ObservableList<String> data.
#Override
public void start(Stage primaryStage) {
ComboBox<String> title = new ComboBox();
StackPane root = new StackPane();
root.getChildren().add(title);
ObservableList<String> data = FXCollections.observableArrayList();
List<String> test = Arrays.asList("Test", "Example");
for(String s : test) {
data.add(s);
}
title.setItems(data);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
And you will have the expected result:
EDIT
In the case you want to add several items from the database to each item of the combo, you just need to provide a way to render the data, using ComboBox.setCellFactory(), so you can override the default method that produces the string [item1, item2, ... ].

How to create StackPane on the drawn rectangle area

I'm creating UI editor and for that I need to draw UI components on mouse events. I'm stuck on drawing button with caption inside of it. As a result of my searches over stackoverflow I tried to use StackPane for creating Rectangle with caption.
For layout I'm using Group element. The problem is, when I add StackPane to the Group it's being displayed on the top left corner of the Group. However, if I draw just Rectangle itself, it's being displayed on that place, where I'm releasing the mouse.
How to achieve the same effect for StackPane?
Here is my code:
public class Main extends Application {
double startingPointX, startingPointY;
Group rectanglesGroup = new Group();
Rectangle newRectangle = null;
boolean newRectangleIsBeingDrawn = false;
// the following method adjusts coordinates so that the rectangle
// is shown "in a correct way" in relation to the mouse event
void adjustRectanglePRoperties(double startingPointX,
double startingPointY, double endingPointX, double endingPointY,
Rectangle givenRectangle) {
givenRectangle.setX(startingPointX);
givenRectangle.setY(startingPointY);
givenRectangle.setWidth(endingPointX - startingPointX);
givenRectangle.setHeight(endingPointY - startingPointY);
if (givenRectangle.getWidth() < 0) {
givenRectangle.setWidth(-givenRectangle.getWidth());
givenRectangle.setX(givenRectangle.getX()
- givenRectangle.getWidth());
}
if (givenRectangle.getHeight() < 0) {
givenRectangle.setHeight(-givenRectangle.getHeight());
givenRectangle.setY(givenRectangle.getY()
- givenRectangle.getHeight());
}
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Drawing rectangles");
Scene scene = new Scene(rectanglesGroup, 800, 600);
scene.setFill(Color.BEIGE);
scene.setOnMousePressed(e -> {
if (newRectangleIsBeingDrawn == false) {
startingPointX = e.getSceneX();
startingPointY = e.getSceneY();
newRectangle = new Rectangle();
// a non finished rectangle has always the same color
newRectangle.setFill(Color.SNOW); // almost white color
//Line line = new Line(20,120,270,120);
newRectangle.setStroke(Color.BLACK);
newRectangle.setStrokeWidth(1);
newRectangle.getStrokeDashArray().addAll(3.0, 7.0, 3.0, 7.0);
rectanglesGroup.getChildren().add(newRectangle);
newRectangleIsBeingDrawn = true;
}
});
scene.setOnMouseDragged(e -> {
if (newRectangleIsBeingDrawn == true) {
double currentEndingPointX = e.getSceneX();
double currentEndingPointY = e.getSceneY();
adjustRectanglePRoperties(startingPointX, startingPointY,
currentEndingPointX, currentEndingPointY, newRectangle);
}
});
scene.setOnMouseReleased(e->{
if(newRectangleIsBeingDrawn == true){
//now the drawing of the new rectangle is finished
//let's set the final color for the rectangle
/******************Drawing textbox*******************************/
//newRectangle.setFill(Color.WHITE);
//newRectangle.getStrokeDashArray().removeAll(3.0, 7.0, 3.0, 7.0);
/****************************************************************/
/*****************Drawing button*********************************/
Image image = new Image("file:button.png");
ImagePattern buttonImagePattern = new ImagePattern(image);
newRectangle.setFill(buttonImagePattern);
newRectangle.setStroke(Color.WHITE);
newRectangle.getStrokeDashArray().removeAll(3.0,7.0,3.0,7.0);
Text text = new Text("Button");
rectanglesGroup.getChildren().remove(newRectangle);
StackPane stack = new StackPane();
stack.getChildren().addAll(newRectangle, text);
rectanglesGroup.getChildren().add(stack);
/****************************************************************/
colorIndex++; //index for the next color to use
//if all colors have been used we'll start re-using colors
//from the beginning of the array
if(colorIndex>=rectangleColors.length){
colorIndex=0;
}
newRectangle=null;
newRectangleIsBeingDrawn=false;
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm using OnMouseReleased event to create components.
I looked for the setX, setPosition or something like this methods, but couldn't find them in StackPane's methods.
And I don't know how translate methods work. So I didn't try them to achieve my goal.
You should read the documentation about a JavaFX Node.
You can position the nodes absolutely via setLayoutX (and Y) or relative via setTranslateX (and Y), which adds to the current layout position.
A StackPane is just a container and in your case no different to any other Node you want to place on your Scene. Just create it, set the dimensions and location and put it on the Scene.
Your code doesn't work, so I created my own. Here's example code about how to approach this matter:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.StrokeLineCap;
import javafx.stage.Stage;
public class RubberBandSelectionDemo extends Application {
CheckBox drawButtonCheckBox;
public static void main(String[] args) {
launch(args);
}
Pane root;
#Override
public void start(Stage primaryStage) {
root = new Pane();
root.setStyle("-fx-background-color:white");
root.setPrefSize(1024, 768);
drawButtonCheckBox = new CheckBox( "Draw Button");
root.getChildren().add( drawButtonCheckBox);
primaryStage.setScene(new Scene(root, root.getWidth(), root.getHeight()));
primaryStage.show();
new RubberBandSelection(root);
}
public class RubberBandSelection {
final DragContext dragContext = new DragContext();
Rectangle rect;
Pane group;
public RubberBandSelection( Pane group) {
this.group = group;
rect = new Rectangle( 0,0,0,0);
rect.setStroke(Color.BLUE);
rect.setStrokeWidth(1);
rect.setStrokeLineCap(StrokeLineCap.ROUND);
rect.setFill(Color.LIGHTBLUE.deriveColor(0, 1.2, 1, 0.6));
group.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler);
group.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler);
group.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler);
}
EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
dragContext.mouseAnchorX = event.getSceneX();
dragContext.mouseAnchorY = event.getSceneY();
rect.setX(dragContext.mouseAnchorX);
rect.setY(dragContext.mouseAnchorY);
rect.setWidth(0);
rect.setHeight(0);
group.getChildren().add( rect);
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
// get coordinates
double x = rect.getX();
double y = rect.getY();
double w = rect.getWidth();
double h = rect.getHeight();
if( drawButtonCheckBox.isSelected()) {
// create button
Button node = new Button();
node.setDefaultButton(false);
node.setPrefSize(w, h);
node.setText("Button");
node.setLayoutX(x);
node.setLayoutY(y);
root.getChildren().add( node);
} else {
// create rectangle
Rectangle node = new Rectangle( 0, 0, w, h);
node.setStroke( Color.BLACK);
node.setFill( Color.BLACK.deriveColor(0, 0, 0, 0.3));
node.setLayoutX( x);
node.setLayoutY( y);
root.getChildren().add( node);
}
// remove rubberband
rect.setX(0);
rect.setY(0);
rect.setWidth(0);
rect.setHeight(0);
group.getChildren().remove( rect);
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double offsetX = event.getSceneX() - dragContext.mouseAnchorX;
double offsetY = event.getSceneY() - dragContext.mouseAnchorY;
if( offsetX > 0)
rect.setWidth( offsetX);
else {
rect.setX(event.getSceneX());
rect.setWidth(dragContext.mouseAnchorX - rect.getX());
}
if( offsetY > 0) {
rect.setHeight( offsetY);
} else {
rect.setY(event.getSceneY());
rect.setHeight(dragContext.mouseAnchorY - rect.getY());
}
}
};
private final class DragContext {
public double mouseAnchorX;
public double mouseAnchorY;
}
}
}
And here's an image:
The demo shows a rubberband selection which allows you to draw a selection rectangle. Upon release of the mouse button either a rectangle or a button is drawn, depending on the "Draw Button" checkbox selection in the top left corner. If you'd like to draw a StackPane, just change the code accordingly in the mouse released handler.
And of course, if you want to draw the components directly instead of the rubberband, just exchange the Rectangle in the rubberband selection code with e. g. a Button. Here's the Button drawing code only, just replace it in the above example.
public class RubberBandSelection {
final DragContext dragContext = new DragContext();
Button button;
Pane group;
public RubberBandSelection( Pane group) {
this.group = group;
button = new Button();
button.setPrefSize(0, 0);
group.addEventHandler(MouseEvent.MOUSE_PRESSED, onMousePressedEventHandler);
group.addEventHandler(MouseEvent.MOUSE_DRAGGED, onMouseDraggedEventHandler);
group.addEventHandler(MouseEvent.MOUSE_RELEASED, onMouseReleasedEventHandler);
}
EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
dragContext.mouseAnchorX = event.getSceneX();
dragContext.mouseAnchorY = event.getSceneY();
button.setLayoutX(dragContext.mouseAnchorX);
button.setLayoutY(dragContext.mouseAnchorY);
button.setPrefWidth(0);
button.setPrefHeight(0);
group.getChildren().add( button);
}
};
EventHandler<MouseEvent> onMouseReleasedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
// get coordinates
double x = button.getLayoutX();
double y = button.getLayoutY();
double w = button.getWidth();
double h = button.getHeight();
// create button
Button node = new Button();
node.setDefaultButton(false);
node.setPrefSize(w, h);
node.setText("Button");
node.setLayoutX(x);
node.setLayoutY(y);
root.getChildren().add( node);
// remove rubberband
button.setLayoutX(0);
button.setLayoutY(0);
button.setPrefWidth(0);
button.setPrefHeight(0);
group.getChildren().remove( button);
}
};
EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double offsetX = event.getSceneX() - dragContext.mouseAnchorX;
double offsetY = event.getSceneY() - dragContext.mouseAnchorY;
if( offsetX > 0)
button.setPrefWidth( offsetX);
else {
button.setLayoutX(event.getSceneX());
button.setPrefWidth(dragContext.mouseAnchorX - button.getLayoutX());
}
if( offsetY > 0) {
button.setPrefHeight( offsetY);
} else {
button.setLayoutY(event.getSceneY());
button.setPrefHeight(dragContext.mouseAnchorY - button.getLayoutY());
}
}
};
private final class DragContext {
public double mouseAnchorX;
public double mouseAnchorY;
}
}

Resources