JavaFx - 获取其父节点不是 Pane 的节点或控件的坐标 (x,y)
JavaFx - Get the coordinates(x,y) of a node or control whose parent is not a Pane
我正在尝试模拟一个弹出容器,它会显示一些关于正确地址格式的提示。只要 addressTextfield
获得焦点,就会显示弹出窗口。弹出窗口应出现在 addressTextfield
下方。问题是,我在布局中使用了 VBox
、HBox
和 FlowPane
的组合。默认的 layoutX
和 layoutY
是零,看起来它们在运行时不会改变。
我的弹出控件
我的地址字段和层次结构
到目前为止我得到了什么...
我的 Popup 控件保持在顶部。我尝试将我的弹出窗口 layoutXProperty()
绑定到 addressTextFields
的 layoutXProperty()
same in layoutYProperty()
。我尝试在 addressTextField
上添加一个 MouseEvent.MOUSE_CLICKED
,添加一个将在 MouseEvent.MouseClicked
上更新的 MouseLocationProperty
,并将其绑定到我的弹出窗口的 layoutXProperty()
。但是仍然没有让它出现在 addressTextField
.
下
我的添加新帐户Class
package com.strongandwhite.pages.dentistadnstaff;
import com.strongandwhite.customcontrols.CustomComboBox;
import com.strongandwhite.customcontrols.CustomDatePicker;
import com.strongandwhite.customcontrols.CustomPasswordField;
import com.strongandwhite.customcontrols.CustomTextField;
import com.strongandwhite.main.MainWindow;
import com.strongandwhite.models.User;
import com.strongandwhite.pages.Page;
import com.strongandwhite.rules.*;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import java.io.IOException;
import java.time.LocalDate;
import java.time.chrono.ChronoLocalDate;
import java.util.ArrayList;
public class AddNewAccount extends Page {
private ArrayList<String> gender;
private ArrayList<String> type;
private ArrayList<String> position;
public User user;
private SimpleDoubleProperty mouseX;
private SimpleDoubleProperty mouseY;
@FXML private HBox firstNameHBox;
private CustomTextField firstNameTextField;
@FXML private HBox middleNameHBox;
private CustomTextField middleNameTextField;
@FXML private HBox lastNameHBox;
private CustomTextField lastNameTextField;
@FXML private HBox ageHBox;
private CustomTextField ageTextField;
@FXML private HBox genderHBox;
private CustomComboBox<String> genderComboBox;
@FXML private HBox addressHBox;
private CustomTextField addressTextField;
@FXML private HBox contactHBox;
private CustomTextField contactTextField;
@FXML private HBox nationalityHBox;
private CustomTextField nationalityTextField;
@FXML private HBox religionHBox;
private CustomTextField religionTextField;
@FXML private HBox emailAddressHBox;
private CustomTextField emailAddressTextField;
@FXML private HBox birthdateHBox;
private CustomDatePicker birtdateDatePicker;
@FXML private HBox accountIDHBox;
private CustomTextField accountIDTextField;
@FXML private HBox passwordHBox;
private CustomPasswordField passwordTextField;
@FXML private HBox confirmPasswordHBox;
private CustomPasswordField confirmPasswordTextField;
@FXML private HBox accountTypeHBox;
private CustomComboBox<String> accountTypeComboBox;
@FXML private HBox positionHBox;
private CustomComboBox<String> positionComboBox;
@FXML private HBox question1HBox;
private CustomTextField question1TextField;
@FXML private HBox question2HBox;
private CustomTextField question2TextField;
@FXML private HBox question3HBox;
private CustomTextField question3TextField;
@FXML private HBox answer1HBox;
private CustomTextField answer1TextField;
@FXML private HBox answer2HBox;
private CustomTextField answer2TextField;
@FXML private HBox answer3HBox;
private CustomTextField answer3TextField;
@FXML private Button clearButton;
private AnchorPane addressInfo;
private Pane coverPane;
private ScrollPane scrollPane;
public AddNewAccount(User user, MainWindow mainWindow) {
this.user = user;
FXMLLoader loader = new FXMLLoader(getClass().getResource("AddNewAccount.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
loadTitle("AddNewAccountTitle.fxml");
FXMLLoader loader1 = new FXMLLoader(getClass().getResource("AddressInfo.fxml"));
try {
addressInfo = loader1.load();
} catch (IOException e) {
e.printStackTrace();
}
coverPane = new Pane();
firstNameTextField = new CustomTextField(firstNameHBox, customControls);
firstNameTextField.setRule(new NameRule("First Name"));
middleNameTextField = new CustomTextField(middleNameHBox, customControls);
middleNameTextField.setRule(new NameRule("Middle Name"));
lastNameTextField = new CustomTextField(lastNameHBox, customControls);
lastNameTextField.setRule(new NameRule("Last Name"));
birtdateDatePicker = new CustomDatePicker(birthdateHBox, customControls);
birtdateDatePicker.setRule(new DateRule());
ageTextField = new CustomTextField(ageHBox, customControls);
ageTextField.setRule(new NumbersOnlyRule());
genderComboBox = new CustomComboBox<>(genderHBox, customControls);
genderComboBox.setRule(new WordRule("Gender"));
addressTextField = new CustomTextField(addressHBox, customControls);
addressTextField.setRule(new AddressRule());
contactTextField = new CustomTextField(contactHBox, customControls);
contactTextField.setRule(new ContactNumberRule());
nationalityTextField = new CustomTextField(nationalityHBox, customControls);
nationalityTextField.setRule(new NameRule("Nationality"));
religionTextField = new CustomTextField(religionHBox, customControls);
religionTextField.setRule(new NameRule("Religion"));
emailAddressTextField = new CustomTextField(emailAddressHBox, customControls);
emailAddressTextField.setRule(new EmailAddressRule());
accountIDTextField = new CustomTextField(accountIDHBox, customControls);
accountIDTextField.setRule(new AccountIDRule());
passwordTextField = new CustomPasswordField(passwordHBox, customControls);
passwordTextField.setRule(new PasswordRule());
confirmPasswordTextField = new CustomPasswordField(confirmPasswordHBox, customControls);
confirmPasswordTextField.setRule(new PasswordRule());
accountTypeComboBox = new CustomComboBox<>(accountTypeHBox, customControls);
accountTypeComboBox.setRule(new WordRule("Account Type"));
positionComboBox = new CustomComboBox<>(positionHBox, customControls);
positionComboBox.setRule(new WordRule("Position"));
question1TextField = new CustomTextField(question1HBox, customControls);
question1TextField.setRule(new WordRule("Question"));
question2TextField = new CustomTextField(question2HBox, customControls);
question2TextField.setRule(new WordRule("Question"));
question3TextField = new CustomTextField(question3HBox, customControls);
question3TextField.setRule(new WordRule("Question"));
answer1TextField = new CustomTextField(answer1HBox, customControls);
answer1TextField.setRule(new WordRule("Answer"));
answer2TextField = new CustomTextField(answer2HBox, customControls);
answer2TextField.setRule(new WordRule("Answer"));
answer3TextField = new CustomTextField(answer3HBox, customControls);
answer3TextField.setRule(new WordRule("Answer"));
clearButton.setOnAction(event -> clearPageFields());
birtdateDatePicker.setDefaultDate(LocalDate.now().minusYears(18));
birtdateDatePicker.setDayCellFactory(param -> new DateCell() {
@Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if(item.isBefore(ChronoLocalDate.from(LocalDate.now().minusYears(76).minusMonths(1)))||item.isAfter(ChronoLocalDate.from(LocalDate.now().minusYears(18).plusMonths(1)))) {
this.setDisable(true);
}
}
});
user.ageProperty().bind(birtdateDatePicker.ageProperty());
ageTextField.textProperty().bind(user.ageProperty().asString());
gender = new ArrayList<>();
gender.add("Male");
gender.add("Female");
genderComboBox.setItems(gender);
type = new ArrayList<>();
type.add("Administrator");
type.add("Standard");
type.add("Limited");
accountTypeComboBox.setItems(type);
position = new ArrayList<>();
position.add("Dentist");
position.add("Receptionist");
position.add("Staff");
positionComboBox.setItems(position);
answer1TextField.editableProperty().bind(question1TextField.textProperty().isNotEmpty());
answer1TextField.editableProperty().addListener(event-> {
if(question1TextField.textProperty().getValue().trim().isEmpty()) answer1TextField.clear();
});
answer2TextField.editableProperty().bind(question2TextField.textProperty().isNotEmpty());
answer2TextField.editableProperty().addListener(event-> {
if(question2TextField.textProperty().getValue().trim().isEmpty()) answer2TextField.clear();
});
answer3TextField.editableProperty().bind(question3TextField.textProperty().isNotEmpty());
answer3TextField.editableProperty().addListener(event-> {
if(question3TextField.textProperty().getValue().trim().isEmpty()) answer3TextField.clear();
});
mainWindow.getActivePagePane().getChildren().add(getPageTitle());
scrollPane = (ScrollPane) mainWindow.getActivePagePane().getChildren().get(0);
scrollPane.vvalueProperty().addListener(event-> scrollPane.requestFocus());
addressInfo.visibleProperty().bind(addressTextField.getTextField().focusedProperty());
coverPane.setPickOnBounds(false);
mainWindow.getActivePagePane().getChildren().add(coverPane);
coverPane.getChildren().add(addressInfo);
addressInfo.layoutXProperty().bind(addressTextField.getTextField().layoutXProperty());
addressInfo.layoutYProperty().bind(addressTextField.getTextField().layoutYProperty());
}
}
我的自定义文本字段Class
package com.strongandwhite.customcontrols;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import java.util.ArrayList;
public class CustomTextField extends CustomControl {
private TextField textField;
private Label textLabel;
private Button clearButton;
public CustomTextField(HBox control, ArrayList<CustomControl> customControls) {
setContainer(control);
textLabel = (Label) ((VBox)control.getChildren().get(0)).getChildren().get(0);
setErrorLabel((Label) ((VBox)control.getChildren().get(0)).getChildren().get(2));
textField = (TextField) ((StackPane)((VBox)control.getChildren().get(0)).getChildren().get(1)).getChildren().get(0);
clearButton = (Button) ((StackPane)((VBox)control.getChildren().get(0)).getChildren().get(1)).getChildren().get(1);
textLabel.visibleProperty().bind(textField.textProperty().isNotEmpty());
clearButton.visibleProperty().bind(textField.textProperty().isNotEmpty().and(textField.focusedProperty()).and(textField.editableProperty()));
clearButton.setOnAction(event -> textField.clear());
textField.textProperty().addListener((observable, oldValue, newValue) -> executeRule(getRule(), textField.getText()));
customControls.add(this);
}
public StringProperty textProperty() {
return textField.textProperty();
}
public BooleanProperty editableProperty() {
return textField.editableProperty();
}
public String getText() {
return textField.getText();
}
public void setText(String text) {
textField.setText(text);
}
public TextField getTextField() {
return textField;
}
public void setTextField(TextField textField) {
this.textField = textField;
}
@Override
public void clear() {
textField.clear();
}
}
有什么方法可以获取 addressTextField
相对于我的表单的坐标吗?
注意:我的弹出窗口添加在 Pane
特别是 coverPane
上面,它们都在 StackPane
.
下
建议您使用类似的东西:
Bounds boundsInScene = addressTextField.localToScene(addressTextField.getBoundsInLocal());
然后使用
boundsInScene.getMinX()
boundsInScene.getMinY()
boundsInScene.getMaxX()
boundsInScene.getMaxY()
boundsInScene.getWidth()
boundsInScene.getHeight()
获取组件相对于场景的值
我正在尝试模拟一个弹出容器,它会显示一些关于正确地址格式的提示。只要 addressTextfield
获得焦点,就会显示弹出窗口。弹出窗口应出现在 addressTextfield
下方。问题是,我在布局中使用了 VBox
、HBox
和 FlowPane
的组合。默认的 layoutX
和 layoutY
是零,看起来它们在运行时不会改变。
我的弹出控件
我的地址字段和层次结构
到目前为止我得到了什么...
我的 Popup 控件保持在顶部。我尝试将我的弹出窗口 layoutXProperty()
绑定到 addressTextFields
的 layoutXProperty()
same in layoutYProperty()
。我尝试在 addressTextField
上添加一个 MouseEvent.MOUSE_CLICKED
,添加一个将在 MouseEvent.MouseClicked
上更新的 MouseLocationProperty
,并将其绑定到我的弹出窗口的 layoutXProperty()
。但是仍然没有让它出现在 addressTextField
.
我的添加新帐户Class
package com.strongandwhite.pages.dentistadnstaff;
import com.strongandwhite.customcontrols.CustomComboBox;
import com.strongandwhite.customcontrols.CustomDatePicker;
import com.strongandwhite.customcontrols.CustomPasswordField;
import com.strongandwhite.customcontrols.CustomTextField;
import com.strongandwhite.main.MainWindow;
import com.strongandwhite.models.User;
import com.strongandwhite.pages.Page;
import com.strongandwhite.rules.*;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.DateCell;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import java.io.IOException;
import java.time.LocalDate;
import java.time.chrono.ChronoLocalDate;
import java.util.ArrayList;
public class AddNewAccount extends Page {
private ArrayList<String> gender;
private ArrayList<String> type;
private ArrayList<String> position;
public User user;
private SimpleDoubleProperty mouseX;
private SimpleDoubleProperty mouseY;
@FXML private HBox firstNameHBox;
private CustomTextField firstNameTextField;
@FXML private HBox middleNameHBox;
private CustomTextField middleNameTextField;
@FXML private HBox lastNameHBox;
private CustomTextField lastNameTextField;
@FXML private HBox ageHBox;
private CustomTextField ageTextField;
@FXML private HBox genderHBox;
private CustomComboBox<String> genderComboBox;
@FXML private HBox addressHBox;
private CustomTextField addressTextField;
@FXML private HBox contactHBox;
private CustomTextField contactTextField;
@FXML private HBox nationalityHBox;
private CustomTextField nationalityTextField;
@FXML private HBox religionHBox;
private CustomTextField religionTextField;
@FXML private HBox emailAddressHBox;
private CustomTextField emailAddressTextField;
@FXML private HBox birthdateHBox;
private CustomDatePicker birtdateDatePicker;
@FXML private HBox accountIDHBox;
private CustomTextField accountIDTextField;
@FXML private HBox passwordHBox;
private CustomPasswordField passwordTextField;
@FXML private HBox confirmPasswordHBox;
private CustomPasswordField confirmPasswordTextField;
@FXML private HBox accountTypeHBox;
private CustomComboBox<String> accountTypeComboBox;
@FXML private HBox positionHBox;
private CustomComboBox<String> positionComboBox;
@FXML private HBox question1HBox;
private CustomTextField question1TextField;
@FXML private HBox question2HBox;
private CustomTextField question2TextField;
@FXML private HBox question3HBox;
private CustomTextField question3TextField;
@FXML private HBox answer1HBox;
private CustomTextField answer1TextField;
@FXML private HBox answer2HBox;
private CustomTextField answer2TextField;
@FXML private HBox answer3HBox;
private CustomTextField answer3TextField;
@FXML private Button clearButton;
private AnchorPane addressInfo;
private Pane coverPane;
private ScrollPane scrollPane;
public AddNewAccount(User user, MainWindow mainWindow) {
this.user = user;
FXMLLoader loader = new FXMLLoader(getClass().getResource("AddNewAccount.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
loadTitle("AddNewAccountTitle.fxml");
FXMLLoader loader1 = new FXMLLoader(getClass().getResource("AddressInfo.fxml"));
try {
addressInfo = loader1.load();
} catch (IOException e) {
e.printStackTrace();
}
coverPane = new Pane();
firstNameTextField = new CustomTextField(firstNameHBox, customControls);
firstNameTextField.setRule(new NameRule("First Name"));
middleNameTextField = new CustomTextField(middleNameHBox, customControls);
middleNameTextField.setRule(new NameRule("Middle Name"));
lastNameTextField = new CustomTextField(lastNameHBox, customControls);
lastNameTextField.setRule(new NameRule("Last Name"));
birtdateDatePicker = new CustomDatePicker(birthdateHBox, customControls);
birtdateDatePicker.setRule(new DateRule());
ageTextField = new CustomTextField(ageHBox, customControls);
ageTextField.setRule(new NumbersOnlyRule());
genderComboBox = new CustomComboBox<>(genderHBox, customControls);
genderComboBox.setRule(new WordRule("Gender"));
addressTextField = new CustomTextField(addressHBox, customControls);
addressTextField.setRule(new AddressRule());
contactTextField = new CustomTextField(contactHBox, customControls);
contactTextField.setRule(new ContactNumberRule());
nationalityTextField = new CustomTextField(nationalityHBox, customControls);
nationalityTextField.setRule(new NameRule("Nationality"));
religionTextField = new CustomTextField(religionHBox, customControls);
religionTextField.setRule(new NameRule("Religion"));
emailAddressTextField = new CustomTextField(emailAddressHBox, customControls);
emailAddressTextField.setRule(new EmailAddressRule());
accountIDTextField = new CustomTextField(accountIDHBox, customControls);
accountIDTextField.setRule(new AccountIDRule());
passwordTextField = new CustomPasswordField(passwordHBox, customControls);
passwordTextField.setRule(new PasswordRule());
confirmPasswordTextField = new CustomPasswordField(confirmPasswordHBox, customControls);
confirmPasswordTextField.setRule(new PasswordRule());
accountTypeComboBox = new CustomComboBox<>(accountTypeHBox, customControls);
accountTypeComboBox.setRule(new WordRule("Account Type"));
positionComboBox = new CustomComboBox<>(positionHBox, customControls);
positionComboBox.setRule(new WordRule("Position"));
question1TextField = new CustomTextField(question1HBox, customControls);
question1TextField.setRule(new WordRule("Question"));
question2TextField = new CustomTextField(question2HBox, customControls);
question2TextField.setRule(new WordRule("Question"));
question3TextField = new CustomTextField(question3HBox, customControls);
question3TextField.setRule(new WordRule("Question"));
answer1TextField = new CustomTextField(answer1HBox, customControls);
answer1TextField.setRule(new WordRule("Answer"));
answer2TextField = new CustomTextField(answer2HBox, customControls);
answer2TextField.setRule(new WordRule("Answer"));
answer3TextField = new CustomTextField(answer3HBox, customControls);
answer3TextField.setRule(new WordRule("Answer"));
clearButton.setOnAction(event -> clearPageFields());
birtdateDatePicker.setDefaultDate(LocalDate.now().minusYears(18));
birtdateDatePicker.setDayCellFactory(param -> new DateCell() {
@Override
public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if(item.isBefore(ChronoLocalDate.from(LocalDate.now().minusYears(76).minusMonths(1)))||item.isAfter(ChronoLocalDate.from(LocalDate.now().minusYears(18).plusMonths(1)))) {
this.setDisable(true);
}
}
});
user.ageProperty().bind(birtdateDatePicker.ageProperty());
ageTextField.textProperty().bind(user.ageProperty().asString());
gender = new ArrayList<>();
gender.add("Male");
gender.add("Female");
genderComboBox.setItems(gender);
type = new ArrayList<>();
type.add("Administrator");
type.add("Standard");
type.add("Limited");
accountTypeComboBox.setItems(type);
position = new ArrayList<>();
position.add("Dentist");
position.add("Receptionist");
position.add("Staff");
positionComboBox.setItems(position);
answer1TextField.editableProperty().bind(question1TextField.textProperty().isNotEmpty());
answer1TextField.editableProperty().addListener(event-> {
if(question1TextField.textProperty().getValue().trim().isEmpty()) answer1TextField.clear();
});
answer2TextField.editableProperty().bind(question2TextField.textProperty().isNotEmpty());
answer2TextField.editableProperty().addListener(event-> {
if(question2TextField.textProperty().getValue().trim().isEmpty()) answer2TextField.clear();
});
answer3TextField.editableProperty().bind(question3TextField.textProperty().isNotEmpty());
answer3TextField.editableProperty().addListener(event-> {
if(question3TextField.textProperty().getValue().trim().isEmpty()) answer3TextField.clear();
});
mainWindow.getActivePagePane().getChildren().add(getPageTitle());
scrollPane = (ScrollPane) mainWindow.getActivePagePane().getChildren().get(0);
scrollPane.vvalueProperty().addListener(event-> scrollPane.requestFocus());
addressInfo.visibleProperty().bind(addressTextField.getTextField().focusedProperty());
coverPane.setPickOnBounds(false);
mainWindow.getActivePagePane().getChildren().add(coverPane);
coverPane.getChildren().add(addressInfo);
addressInfo.layoutXProperty().bind(addressTextField.getTextField().layoutXProperty());
addressInfo.layoutYProperty().bind(addressTextField.getTextField().layoutYProperty());
}
}
我的自定义文本字段Class
package com.strongandwhite.customcontrols;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import java.util.ArrayList;
public class CustomTextField extends CustomControl {
private TextField textField;
private Label textLabel;
private Button clearButton;
public CustomTextField(HBox control, ArrayList<CustomControl> customControls) {
setContainer(control);
textLabel = (Label) ((VBox)control.getChildren().get(0)).getChildren().get(0);
setErrorLabel((Label) ((VBox)control.getChildren().get(0)).getChildren().get(2));
textField = (TextField) ((StackPane)((VBox)control.getChildren().get(0)).getChildren().get(1)).getChildren().get(0);
clearButton = (Button) ((StackPane)((VBox)control.getChildren().get(0)).getChildren().get(1)).getChildren().get(1);
textLabel.visibleProperty().bind(textField.textProperty().isNotEmpty());
clearButton.visibleProperty().bind(textField.textProperty().isNotEmpty().and(textField.focusedProperty()).and(textField.editableProperty()));
clearButton.setOnAction(event -> textField.clear());
textField.textProperty().addListener((observable, oldValue, newValue) -> executeRule(getRule(), textField.getText()));
customControls.add(this);
}
public StringProperty textProperty() {
return textField.textProperty();
}
public BooleanProperty editableProperty() {
return textField.editableProperty();
}
public String getText() {
return textField.getText();
}
public void setText(String text) {
textField.setText(text);
}
public TextField getTextField() {
return textField;
}
public void setTextField(TextField textField) {
this.textField = textField;
}
@Override
public void clear() {
textField.clear();
}
}
有什么方法可以获取 addressTextField
相对于我的表单的坐标吗?
注意:我的弹出窗口添加在 Pane
特别是 coverPane
上面,它们都在 StackPane
.
Bounds boundsInScene = addressTextField.localToScene(addressTextField.getBoundsInLocal());
然后使用
boundsInScene.getMinX()
boundsInScene.getMinY()
boundsInScene.getMaxX()
boundsInScene.getMaxY()
boundsInScene.getWidth()
boundsInScene.getHeight()
获取组件相对于场景的值