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;
}
}
Related
I am very new to Java so please be patient with me. I have successfully added buttons, labels and even a progress bar to a listview cell. I need to be able to detect when one of the buttons has been clicked. Adding controls to listview content I managed to get from a couple of posts here the code i am using is shown below
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class ListViewDemo extends Application {
public static class lvCell extends VBox {
Label labelName = new Label();
Label labelPath = new Label();
Label labelElapse = new Label();
Button buttonPlayPause = new Button();
Button buttonStop = new Button();
ImageView ivStop = new ImageView();
ImageView ivPlay = new ImageView();
Pane buttonSpacer = new Pane();
Pane progressBarSpacer = new Pane();
HBox hbDetail = new HBox();
HBox hbProgress = new HBox();
ProgressBar pbProgress = new ProgressBar();
File filePlay;
File fileStop;
double prefWidth = 10;
double prefHeight = 10;
lvCell(String labelText) {
super();
labelName.setText(labelText);
labelName.setMaxWidth(Double.MAX_VALUE);
labelPath.setMaxWidth(0);
labelPath.setText("Path");
pbProgress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(labelName, Priority.ALWAYS);
HBox.setHgrow(pbProgress, Priority.ALWAYS);
HBox.setMargin(labelName, new Insets(5, 0, 0, 0));
HBox.setMargin(pbProgress, new Insets(0, 0, 0, 0));
labelPath.setVisible(false);
buttonSpacer.setPrefSize(prefWidth, prefHeight);
labelElapse.setPrefSize(50, prefHeight);
labelElapse.setText("Time");;
progressBarSpacer.setPrefSize(prefWidth * 6, prefHeight);
filePlay = new File("src/image/play.png");
fileStop = new File("src/image/stop.png");
Image imagePlay = new Image(filePlay.toURI().toString());
Image imageStop = new Image(fileStop.toURI().toString());
ivPlay.setImage(imagePlay);
ivStop.setImage(imageStop);
ivPlay.setFitHeight(prefHeight);
ivPlay.setFitWidth(prefWidth);
ivStop.setFitHeight(prefHeight);
ivStop.setFitWidth(prefWidth);
buttonPlayPause.setGraphic(ivPlay);
buttonStop.setGraphic(ivStop);
buttonPlayPause.setMaxSize(prefWidth, prefHeight);
buttonStop.setMaxSize(prefWidth, prefHeight);
pbProgress.setMaxHeight(2);
pbProgress.setPrefHeight(2);
hbDetail.getChildren().addAll(buttonPlayPause, buttonStop, buttonSpacer, labelName, labelPath);
hbProgress.getChildren().addAll(progressBarSpacer, pbProgress, labelElapse);
this.getChildren().addAll(hbDetail, hbProgress);
}
}
public Parent createContent() {
BorderPane layout = new BorderPane();
List < lvCell > list = new ArrayList < > ();
for (int i = 0; i < 10; i++) {
list.add(new lvCell("Item " + i));
}
ListView < lvCell > listView = new ListView < lvCell > ();
ObservableList < lvCell > myObservableList = FXCollections.observableList(list);
listView.setItems(myObservableList);
layout.setCenter(listView);
return layout;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(200);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
The screen looks like this:
Any help will be greatly appreciated.
Thanks in advance, and wishing you a peaceful journey.
Yas
This is not a class well designed to put into a ListView. An object used as item in a ListView should contain data; the ListCell implementation produced by the cellFactory is responsible for determining the visual representation of the data in the ListView. This way you avoid the creation of nodes for every object reducing the memory footprint, which is exactly what ListView is designed for.
Simplified example
The data here contains just the progress and some text; it's displayed in a ProgressBar and the text of the cell; an additional button in the cell allows increasing the progress by 0.25 for each click and removing any items reaching a progress of 1.
Data class
public class Data {
private final DoubleProperty progress = new SimpleDoubleProperty();
private final String text;
public Data(String text) {
this.text = text;
}
public double getProgress() {
return progress.get();
}
public void setProgress(double value) {
progress.set(value);
}
public String getText() {
return text;
}
public ObservableValue<? extends Number> progressProperty() {
return progress;
}
}
ListView code
ListView<Data> listView = new ListView<>(someData);
listView.setCellFactory(l -> new ListCell<Data>() {
private final ProgressBar progressBar = new ProgressBar();
private final Button button = new Button("increase");
private final HBox content = new HBox(progressBar, button);
{
button.setOnAction(evt -> {
Data item = getItem();
int index = getIndex();
double progress = item.getProgress() + 0.25;
item.setProgress(progress);
if (progress >= 1) {
getListView().getItems().remove(index);
}
});
}
#Override
protected void updateItem(Data item, boolean empty) {
super.updateItem(item, empty);
progressBar.progressProperty().unbind();
if (item == null) {
setGraphic(null);
setText("");
} else {
setGraphic(content);
setText(item.getText());
progressBar.progressProperty().bind(item.progressProperty());
}
}
});
I have a javafx application with multiple textboxes that the user can enter information in. I also have a keyboard built into the application that when pressed adds that text to the textbox.
My issue is that since I have multiple textboxes, I don't know which one to add the buttons text to. Is there a way in javafx to check if a user has clicked on a certain textbox so I can check which one has been selected and add the text there?
You can use the Scene.focusOwner property of the active scene to get the focused node. Check, if it's a TextInputControl and call the appropriate method for the button clicked. Note that clicking a button may move the focus, if focusTraversable is true for that button. (By default this is the case.)
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
final Scene scene = new Scene(grid);
for (int i = 0; i < 4; i++) {
grid.add(new TextField(), 0, i);
final String buttonValue = Character.toString((char) ('a'+i));
Button button = new Button(buttonValue);
button.setFocusTraversable(false); // prevent buttons from stealing focus
button.setOnAction(evt -> {
Node fo = scene.getFocusOwner();
if (fo instanceof TextInputControl) {
((TextInputControl) fo).replaceSelection(buttonValue);
}
});
grid.add(button, 1, i);
}
primaryStage.setScene(scene);
primaryStage.show();
}
You should create a listener for each TextField's focusProperty and set an instance variable.
Once you have a global reference to the currently focused TextField, you can do any processing on it that you choose.
Here is a quick application to demonstrate. I've included a couple extra details in the code itself:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
// Instance variable to hold the currently-selected TextField
private TextField selectedTextField;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Create TextFields
TextField txt1 = new TextField();
TextField txt2 = new TextField();
TextField txt3 = new TextField();
TextField txt4 = new TextField();
// This method sets the same change listener on each textfield
installListener(txt1, txt2, txt3, txt4);
VBox pane = new VBox(5);
pane.setPadding(new Insets(5));
// Add the TextFields to the layout
pane.getChildren().addAll(
new HBox(5, new Label("Txt1: "), txt1),
new HBox(5, new Label("Txt2: "), txt2),
new HBox(5, new Label("Txt3: "), txt3),
new HBox(5, new Label("Txt4: "), txt4)
);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
// Accepts multiple TextFields
private void installListener(TextField... textFields) {
// Install the same listener on all of them
for (TextField textField : textFields) {
textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {
// Set the selectedTextField to null whenever focus is lost. This accounts for the
// TextField losing focus to another control that is NOT a TextField
selectedTextField = null;
if (newValue) {
// The new textfield is focused, so set the global reference
selectedTextField = textField;
System.out.println("Selected Text: " + selectedTextField.getText());
}
});
}
}
}
I created about 10 buttons in javafx each of them onclick is suppose to change the label field in a certain way. My problem is that I don't want to create 10 different methods for each label I will like to use one method then test the id of the button if correct I preform what I want
example of what I am asking
if (button.id == Info_205_btn) {
System.out.println("clicked");
subject_name.setText("stanly");
}
This is an update after #math answer
Here is the code I did
#FXML
private void chooseSubject() {
for (int i = 0; i < buttonInfo.length; i++) {
buttonInfo[i] = new Button("Info"+i);
buttonInfo[i].setId("Info"+i);
int finalI = i;
buttonInfo[i].setOnAction(event -> checkID(buttonInfo[finalI]));
}
}
#FXML
private void checkID(Button button){
System.out.println("running");
if (button.getId().equals("Info0")) {
System.out.println("clicked");
subject_name.setText("stanly");
}
else if (button.getId().equals("Info1")) {
System.out.println("clicked");
subject_name.setText("stanly1");
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
chooseSubject();
}
also on click I placed the method chooseSubject in FXML controller
For all of your buttons I think you will still need to put a .setOnAction but you can have them all point to the same function
button.setOnAction(event -> checkID(button));
and from that function check the id
private void checkID(Button button){
if (button.getId().equals("Info_205_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
else if (button.getId().equals("Info_206_btn")) {
System.out.println("clicked");
button.setText("stanly");
}
//So on
}
Also if you put all of your buttons into a list or if they are already in a list you can iterate though the list and do the .setOnAction that way
for (int i = 0; i < buttonList.length; i++)
button[i].setOnAction(event -> checkId((Button) event.getSource()));
Here is a test program I just wrote to give you an example
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button[] buttonList = new Button[10];
for (int i = 0; i < buttonList.length; i++) {
buttonList[i] = new Button("Button "+i);
buttonList[i].setId("Button"+i);
buttonList[i].setOnAction(event -> checkId((Button) event.getSource()));
}
VBox root = new VBox();
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(buttonList);
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setWidth(200);
stage.setScene(scene);
stage.show();
}
private void checkId(Button button) {
for (int i = 0; i <= 10; i++) {
if(button.getId().equals("Button" + i))
if(!button.getText().equals("Button " + i + " Clicked"))
button.setText("Button " + i + " Clicked");
else
button.setText("Button " + i);
}
}
public static void main(String[] args) { launch(args); }
}
Edit: Got carried away
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, ... ].
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.