The searchField is a TextField that only accept numbers. I did it with the code below.
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue.matches("\\d*")) {
searchField.setText(newValue.replaceAll("[^\\d]", ""));
}
});
Now I want the TextField to show a red warning when user tries to input a letter. Like this..example
ControlsFX has a class called CustomTextField that allows you to set a Node on the left or right side of the TextField.
As for the logic (taking some from a previous answer), here's what you would do:
ImageView errorView = new ImageView();
errorView.setImage(new Image("error.png"));
CustomTextField searchField = new CustomTextField();
searchField.setRight(errorView);
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue.matches("\\d*")) {
searchField.setText(newValue.replaceAll("[^\\d]", ""));
searchField.setStyle("-fx-text-box-border: red; -fx-focus-color: red ;");
errorView.setVisible(true);
}else if(!searchField.getStyle().equals("")){
searchField.setStyle("");
errorView.setVisible(false);
}
});
Here is what your looking for if you set the style of the border to red when its incorrect it will simulate what you want to see and set it back to normal when the key event is correct
searchField.textProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue.matches("\\d*")) {
searchField.setText(newValue.replaceAll("[^\\d]", ""));
searchField.setStyle("-fx-text-box-border: red; -fx-focus-color: red ;");
//stopIcon.setVisible(true)
}else if(!searchField.getStyle().equals("")){
searchField.setStyle("");
//stopIcon.setVisible(false)
}
});
If you want the stop sign like in your picture you can probably load an icon in and set it to visible and not visible with the code stiling
I think you should create your own Control as following :
-First you need to put your TextField in a Layout.
-Then add a Label with the exclamation sign aligned to the center.
-After that you need to edit the shape of the Label.
-And finally make a condition to the visibility of the this one to appear according to the input.
Related
I have made a few buttons(each represents a city) on SceneBuilder. I need to set their color according to the number of houses in each city. Darker indicating more properties and lighter less (red).
I have assigned each button a fx:id on scene builder and called it in my code but I am not sure how to change it's color by using javafx code.
Can someone help me out, I am very new to Javafx.
#FXML private Button b1 = new Button();
First i was trying to test wether or not color would actually change but it does not change
#FXML
private void test() {
for (House s: list) {
if(s.getHouse().equals("Manchester") > 10000) {
DropShadow s = new DropShadow();
b1.setEffect(s);
b1.setStyle("fx-background-color: #FF0000");
}
}
}
As c0oder pointed out, it was a simple mistake.
Change b1.setStyle("fx-background-color: #FF0000"); to b1.setStyle("-fx-background-color: #FF0000");
This did the trick.
You can change the buttons color directly through a property rather than manipulating the style.
Here's an example of changing the text in the button to red:
button.setTextFill(Color.RED);
This would be changing the background color:
button.setBackground(new Background(new BackgroundFill(Color.RED, null, null);
I'm having a problem with Label and TextField placement in a gridpane in response to toggled RadioButtons.
The window will display the same options except for two different labels and text fields which depend on which RadioButton the user has selected.(See images attached).
InHouse RB Selected
Outsourced RB Selected
I added the RadioButton objects to a Toggle Group, then coded the "on actions" to add the "Machine ID" or "Company Name" fields to the GridPane as needed when one of the options is selected.
My problem is that I can only select each option once, and the display of the second option only overlaps the first instance instead of replacing it. If I try to switch back again, I get a runtime error(in Netbeans) about adding the same object twice to the grid.
Any code that I have tried that could remove the node from the display had no affect on the menu's behavior.
ArrayList<Label> typeSpecLabels = new ArrayList<Label>();
ArrayList<TextField>typeSpecFields = new ArrayList<TextField>();
typeSpecLabels.add(machineIDLabel);
typeSpecLabels.add(companyLabel);
typeSpecFields.add(machineIDField);
typeSpecFields.add(companyNameField);
inHouseBtn.setOnAction(inHouseSpecificEvent ->
{
typeSpecLabels.add(machineIDLabel);
grid1.add(typeSpecLabels.get(0),0,8,1,1);
grid1.add(typeSpecFields.get(0), 1,8,1,1);
if(outSourceBtn.isArmed() == true){
grid1.getChildren().remove(companyLabel);
grid1.getChildren().remove(companyNameField);
}
});
outSourceBtn.setOnAction(outSourceSpecificEvent ->
{
typeSpecLabels.add(companyLabel);
grid1.add(companyLabel,0,8,1,1);
grid1.add(companyNameField,1,8,1,1);
if(outSourceBtn.isArmed() == true){
grid1.getChildren().remove(machineIDLabel);
grid1.getChildren().remove(machineIDField);
}
});
I have heard that I could try using 2 or 3 different scenes(one for each state of the RadioButtons), so I may try that. But if it can be done the way I have coded it so far, I would prefer to do it that way.
I would suggest to remove all type specific labels and fields from your grid and then add ones that you need. So the code will look like following:
inHouseBtn.setOnAction(inHouseSpecificEvent ->
{
grid1.getChildren().removeAll(machineIDLabel, companyLabel, machineIDField, companyNameField);
grid1.add(machineIDLabel,0,8,1,1);
grid1.add(machineIDField, 1,8,1,1);
});
outSourceBtn.setOnAction(outSourceSpecificEvent ->
{
grid1.getChildren().removeAll(machineIDLabel, companyLabel, machineIDField, companyNameField);
grid1.add(companyLabel,0,8,1,1);
grid1.add(companyNameField,1,8,1,1);
});
This code ended up working, as Pavlo suggested.
Although I just removed the objects specific to the opposing event.
The code works with no errors or overlapping.
inHouseBtn.setOnAction(inHouseSpecificEvent ->
{
grid1.add(machineIDLabel,0,8,1,1);
grid1.add(machineIDField,1,8,1,1);
grid1.getChildren().remove(companyLabel);
grid1.getChildren().remove(companyNameField);
});
outSourceBtn.setOnAction(outSourceSpecificEvent ->
{
grid1.add(companyLabel,0,8,1,1);
grid1.add(companyNameField,1,8,1,1);
grid1.getChildren().remove(machineIDLabel);
grid1.getChildren().remove(machineIDField);
});
I'm quite a newbie on JavaFX and I need to bind the visible property of a Label in a way that, if the value it represents reaches 0, the Label should be invisible. Also, it needs to be updated when the bounded integerProperty value changes.
This is my code:
#FXML
private Label kingRewardLabel;
// many other stuff between
IntegerProperty kingBonus = mainApp.getLocalModel().getMap().kingBonus();
kingBonus.addListener((observable, oldValue, newValue) -> {
if (newValue.equals(0)) {
kingRewardLabel.setVisible(false);
} else {
kingRewardLabel.setText(String.valueOf(newValue.intValue()));
}
});
// testing the listener
kingBonus.setValue(25);
I have already tried to debug a little but everything seems fine, no error, no exception thrown, just the listener does not work, or at least not as I expect, because the Label still show the default text "Label", instead of "25"
You can use simply bindings to achieve this:
kingRewardLabel.textProperty().bind(kingBonus.asString());
kingRewardLabel.visibleProperty().bind(kingBonus.greaterThan(0));
The Label kingRewardLabel will display the value of the IntegerProperty kingBonus and it is only visible if the displayed value is greater than zero.
But, if you want to stay with listeners:
kingBonus.addListener((obs, oldVal, newVal) -> {
kingRewardLabel.setVisible(newVal.intValue() > 0);
kingRewardLabel.setText(newVal.toString());
});
This is almost the same as your listener in the question, but in that case, if the Label became invisible, it will never become visible again as kingRewardLabel.setVisible(true) is never called.
Finally, to answer your question about why the listener is "not working" - there can be two possible reasons:
1) The Label, which one is displayed is not the Label stored in kingRewardLabel
2) At the time when you call kingBonus.setValue(25);, the value stored in kingBonus is already 25, no changed event will be fired, therefore the listener is not executed at all.
You can go like this:
kingBonus.addListener(l -> {
int value = kingBonus.getValue().intValue();
System.out.println("Entered listener for value:" + value);
if (value == 0)
kingRewardLabel.setVisible(false);
else
kingRewardLabel.setText(value+"");
});
});
I'm currently getting in touch with JavaFx. As a starter, I try to write a small calculator.
This calculator contains a TextField showing the expression to be calculated. I am able to put text in there via keyboard or via the buttons of the calculator. Clicking into the TextField with the mouse or navigating via keyboard results in a blinking caret at the right position as expected. But this caret is obviously not backed by the caret property of the TextField, as textField.getCaretPosition(); returns 0 no matter were the blinking "mouse/keyboard-caret" shows up. Moving the "intern" caret with textField.forward() or textField.backward() etc. works just fine.
Is there another property for the "mouse/keyboard-caret"? Please don't tell me I have to listen for mouseclicks and set the caret by myself. The same problem seems to occour for selections, textField.getSelection() returns (0,0), although text is selected(which means, it's blue).
Here's what I'm trying to do in my controller-class. textField.getText() works fine, so the TextField itself should not be the problem.
#FXML
private void onNumberButtonClicked(ActionEvent event){
String formerText = textField.getText();
int pos = textField.getCaretPosition(); //always returns 0, no matter were the cursor is
String additionalText = ((Button)event.getSource()).getText();
textField.setText(formerText.substring(0, pos) +
additionalText +
formerText.substring(pos));
}
Thank you for your help!
The caret position is set to 0 when the TextField looses focus. When you click a button, it gets the focus, therefore the TextField looses it. You can store the old carret position when the control looses focus to fix this:
private int oldCaretPosition;
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
oldCaretPosition = textField.getCaretPosition();
}
});
private void onNumberButtonClicked(ActionEvent event){
String formerText = textField.getText();
String additionalText = ((Button)event.getSource()).getText();
textField.setText(formerText.substring(0, oldCaretPosition)
+ additionalText
+ formerText.substring(oldCaretPosition));
}
Alternatively you can set the focusTraversable property of the Button to false.
How do I set tab width of JavaFX TextArea ?
When I use tabulation (tab key) in TextArea, the width of the tabulation is wide. I want to control the width, i.e., use 4 spaces. In the documentation I could not find a method to do this.
I tried this code (where taInput is a TextArea), but it is not working as it should:
taInput.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.TAB) {
// TAB SPACES
StringBuilder sb = new StringBuilder(config.getTabSpacesCount());
for (int i=0; i<config.getTabSpacesCount(); i++) {
sb.append(' ');
}
taInput.insertText(taInput.getCaretPosition(), sb.toString());
e.consume();
}
}
});
Finally I found a way to do this.
It seems that the setOnKeyPressed() method is not good for this task because the event is handled after the keyPress action is executed.
The addEventFilter() handles the events before their actions are executed, so you can manipulate the events.
My new code:
taInput.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.TAB) {
String s = StringUtils.repeat(' ', config.getTabSpacesCount());
taInput.insertText(taInput.getCaretPosition(), s);
e.consume();
}
}
});
#tenotron
your code also executes same logic for combination of TAB key with set of modifiers ( shift, control, alt, meta or shortcut). Meaning
In TextArea
Pressing TAB key = Ctrl(modifier) + TAB = .... = your logic.
To fix this issue , you have to use KeyCombination
Sample Code :
textArea.addEventFilter(KeyEvent.KEY_PRESSED,
new EventHandler<KeyEvent>() {
final KeyCombination combo = new KeyCodeCombination(
KeyCode.TAB);
#Override
public void handle(KeyEvent event) {
// check for only tab key
if (combo.match(event)) {
textArea.insertText(textArea.getCaretPosition(),
"I am not real TAB");
event.consume();
}
}
});
now Pressing TAB key results "I am not Real TAB" , ctrl+TAB will highlight the next Node on the scene.
Reference :
Correctly Checking KeyEvents
KeyCombination
From JavaFX 14 onward, the best way to deal with this is to use CSS to change the tab width, as shown in my answer to Setting the tab spacing/size visualization for a JavaFX TextArea
Replacing tab characters with multiple spaces doesn't have the same effect as tabs advance to the next tab stop, they don't add a fixed-width gap. Even if you adjusted for the characters preceding the tab, when not using a fixed-width font, an integer number of actual spaces may not give you the correct position.
Try making what you want displayed as a String. Then use s.replace("\t", " ");
if you want four spaces. This worked for me.