I am making a new form using JavaFX. I need a Pop up text field within the form to add new category - forms

adding new category within the same window
I am making a new form using javafx to add new item to an inventory, if I need to add new category into the Item form, I must be able to do within the frame itself by popping up a new text field as shown in the red box. Is there any way to do the same in JavaFX?

Two different approaches. You could use a TextField and setEditable(false). Then make the TextField's setEditable(true) after a double-click on the TextFeild. The first half of the code shows this approach. Another option is to use a Label. When the Label is double-clicked, hide the Label and show a TextField or TextArea. Type your data into one of these nodes and when enter is pressed, remove the TextField or TextArea and show the text in your Label. The second half of the code show this approach.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication7 extends Application {
#Override
public void start(Stage primaryStage) {
VBox root = new VBox();
StackPane stackPane = new StackPane();
TextField textField = new TextField("Text");
textField.setEditable(false);//Set Editiable to false
textField.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
if(mouseEvent.getClickCount() == 2){
textField.setEditable(true);//On double click set editable to true
textField.setOnKeyPressed(event ->{
if(event.getCode().toString().equals("ENTER"))
{
textField.setEditable(false);//On enter set editable to false
}
});
}
}
}
});
Label label = new Label("Test");
VBox.setVgrow(label, Priority.ALWAYS);
label.wrapTextProperty().set(true);
label.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)){
if(mouseEvent.getClickCount() == 2){
label.setVisible(false);
TextArea textarea = new TextArea(label.getText());
textarea.setPrefHeight(label.getHeight() + 10);
stackPane.getChildren().add(textarea);
textarea.setOnKeyPressed(event ->{
System.out.println(event.getCode());
if(event.getCode().toString().equals("ENTER"))
{
label.setText(textarea.getText());
stackPane.getChildren().remove(textarea);
label.setVisible(true);
}
});
}
}
}
});
stackPane.getChildren().add(label);
root.getChildren().add(textField);
root.getChildren().add(stackPane);
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);
}
}

Related

JavaFX Custom Table Cell - Strange behavior

I have this code:
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Example extends Application
{
#Override
public void start(Stage stage) throws Exception
{
TableView<Color> table = new TableView<>();
ObservableList<Color> colors = FXCollections.observableArrayList();
table.setItems(colors);
table.setEditable(true);
TableColumn<Color, Color> column = new TableColumn<>();
column.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue()));
column.setCellFactory(param ->
{
ObservableList<Color> menuColors = FXCollections.observableArrayList();
menuColors.addAll(Color.RED, Color.GREEN, Color.BLUE);
return new ComboBoxTableCell(menuColors);
});
Button button = new Button("Add row");
button.setOnAction(event -> colors.add(Color.BLACK));
VBox box = new VBox(table, button);
table.getColumns().add(column);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
stage.setScene(new Scene(box));
stage.show();
}
public class ComboBoxTableCell extends TableCell<Color, Color>
{
private ComboBox<Color> comboBox;
public ComboBoxTableCell(ObservableList<Color> colors)
{
comboBox = createFancyComboBox(colors);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
public void updateItem(Color item, boolean empty)
{
if (item == null || empty)
setGraphic(null);
else
setGraphic(comboBox);
}
}
private ComboBox<Color> createFancyComboBox(ObservableList<Color> colors)
{
ComboBox<Color> comboBox = new ComboBox<>(colors);
Callback<ListView<Color>, ListCell<Color>> factory = list -> new ColorSquare();
comboBox.setCellFactory(factory);
comboBox.setButtonCell(factory.call(null));
comboBox.setValue(colors.get(0));
return comboBox;
}
public static class ColorSquare extends ListCell<Color>
{
#Override
public void updateItem(Color item, boolean empty)
{
super.updateItem(item, empty);
Rectangle rect = new Rectangle(18, 18);
if (item != null)
{
rect.setFill(item);
setGraphic(rect);
}
}
}
public static void main(String[] args)
{
launch(args);
}
}
If I try to run it, click on the button, change the color to for Green and click 8 times on the button, the green square will disapper.
How do I fix this and why is it happening? The real code isn't much different from this, this is the only problem I have. Thank you.
I have noticed that at times the rerendering of a table cell doesn't work right after a certain number of attempts. I had one where I was updating a remaining amount when the user entered a value in another cell.
To solve this I would toggle visibility of the column.
column.setVisible(false);
column.setVisible(true);
I would do this immediately after the action that changed the value in the cell.
It's a hack but seems to work.

EventFilter consume() does not prevent SpaceChars in TextField

I have a JavaFX GUI where I wish to intercept the pressing of the SpaceBar and use it to call a method. I wrote an EventFilter that seems to do the trick. It includes the command event.consume() which I believe is supposed to keep the KeyEvent from propagating to the various controls.
My issue is that when I added a TextField, and this field has the focus, the Spacebar presses are not being consumed as I thought they would. The " " are captured by the TextField. I would like to intercept and prevent the " " from being added to the TextField.
What am I leaving out in the code below in order to keep " " from reaching the TextField? The api, if I am reading it correctly, says that filters registered with a parent control can intercept an event before it reaches the children nodes. But even when putting the filter directly on the TextField, I am still having " " chars appear in the TextField.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE)
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
The text field is probably listening for KEY_TYPED events. As is well-documented, getCode() returns KeyCode.UNDEFINED for a KEY_TYPED event. Thus you do not catch this case.
You can check for the character variable as well as the code variable to handle all cases:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE || " ".equals(event.getCharacter()))
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
A simple solution i can think,which although doesn't blocks the space from being added to the TextField,but it replaces it after it has been added almost instantly is adding a changeListener to the TextProperty of the TextField:
textField.textProperty().addListener((observable,oldValue,newValue)->{
textField.setText(textField.getText().replace(" ", ""));
});
This may also be helpfull http://fxexperience.com/2012/02/restricting-input-on-a-textfield/

ControlsFX HiddenSidesPane hides When clicked

I am using ControlsFX - HiddenSidesPane where i add some link(ToggleButtons) to be clicked for navigation.
The problem i have is whenever anything is clicked, the HiddenSiddesPane hides.
The desired behavior is when anything inside it is clicked it should not close/hide, unless cursor hovers out of it.
SSCCE to demonstrate undesired behavior
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.HiddenSidesPane;
public class MyHiddenSidesPaneDemo extends Application{
public static void main(String[] args) { Application.launch(args); }
#Override
public void start(Stage primaryStage) throws Exception {
VBox root = new VBox();
TableView tv = new TableView();
HiddenSidesPane hiddenSidesPane = new HiddenSidesPane();
hiddenSidesPane.setContent(tv);
hiddenSidesPane.setLeft(new ListView());
root.getChildren().addAll(hiddenSidesPane);
primaryStage.setTitle("HiddenSidesPane Example Demo");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Try the following:
ListView listView = new ListView();
hiddenSidesPane.setLeft(listView);
listView.setOnMouseEntered(e->hiddenSidesPane.setPinnedSide(Side.LEFT)); //Keep left side pinned
listView.setOnMouseExited(e->hiddenSidesPane.setPinnedSide(null)); //unpin when mouse exits

Can I select text within a label in JavaFX 8 [duplicate]

I just want to create copiable label in JavaFX.
I have tried to create TextField that have no background, have no focus border and default background color, but I have no success.
I have found a lot of questions how to remove focus background from control but all of that looks like "hacks".
Is there are any standard solution to implement copyable text?
You can create a TextField without the border and background color with css:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CopyableLabel extends Application {
#Override
public void start(Stage primaryStage) {
TextField copyable = new TextField("Copy this");
copyable.setEditable(false);
copyable.getStyleClass().add("copyable-label");
TextField tf2 = new TextField();
VBox root = new VBox();
root.getChildren().addAll(copyable, tf2);
Scene scene = new Scene(root, 250, 150);
scene.getStylesheets().add(getClass().getResource("copyable-text.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
and
copyable-text.css:
.copyable-label, .copyable-label:focused {
-fx-background-color: transparent ;
-fx-background-insets: 0px ;
}
This is the solution I used, where there is a small button besides the label to be able to copy the text:
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import org.controlsfx.glyphfont.FontAwesome;
import org.controlsfx.glyphfont.Glyph;
import java.util.Locale;
public class CopiableLabel extends Label
{
public CopiableLabel()
{
addCopyButton();
}
public CopiableLabel(String text)
{
super(text);
addCopyButton();
}
public CopiableLabel(String text, Node graphic)
{
super(text, graphic);
}
private void addCopyButton()
{
Button button = new Button();
button.visibleProperty().bind(textProperty().isEmpty().not());
button.managedProperty().bind(textProperty().isEmpty().not());
button.setFocusTraversable(false);
button.setPadding(new Insets(0.0, 4.0, 0.0, 4.0));
button.setOnAction(actionEvent -> AppUtils.copyToClipboard(getText()));
Glyph clipboardIcon = AppUtils.createFontAwesomeIcon(FontAwesome.Glyph.CLIPBOARD);
clipboardIcon.setFontSize(8.0);
button.setGraphic(clipboardIcon);
setGraphic(button);
setContentDisplay(ContentDisplay.RIGHT);
}
}

JavaFX 8 TextArea loose focus on tab

Is it possible to change the default behaviour of a JavaFX TextArea, so that pressing Tab passes the focus to the next component?
While #ItachiUchiha solution works, as he states, it depends on the layout (box in his sample).
Based on this question, you can modify the default behavior of a TextArea, regardless of the layout.
But you will need to use for this private API, which may change at any time without notice.
In this sample Tab and Shitf+Tab will have the desired behavior, while Ctrl+Tab will insert "\t" on the text area.
#Override
public void start(Stage primaryStage) {
TextArea area = new TextArea();
area.addEventFilter(KeyEvent.KEY_PRESSED, (KeyEvent event) -> {
if (event.getCode() == KeyCode.TAB) {
TextAreaSkin skin = (TextAreaSkin) area.getSkin();
if (skin.getBehavior() instanceof TextAreaBehavior) {
TextAreaBehavior behavior = (TextAreaBehavior) skin.getBehavior();
if (event.isControlDown()) {
behavior.callAction("InsertTab");
} else if (event.isShiftDown()) {
behavior.callAction("TraversePrevious");
} else {
behavior.callAction("TraverseNext");
}
event.consume();
}
}
});
VBox root = new VBox(20, new Button("Button 1"), area, new Button("Button 2"));
Scene scene = new Scene(root, 400, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
Well, you definitely can do this, but it depends on the Layout to which the TextArea is added to. I have created a simple example where a TextArea and a TextField are both added to a VBox. There is a keyEventHandler which monitors the keyPress event on the TextArea and sends the focus to the next child(if any)
import java.util.Iterator;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TextAreaTabFocus extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
VBox box = new VBox();
TextArea textArea = new TextArea();
TextField textField = new TextField();
box.getChildren().addAll(textArea, textField);
final EventHandler<KeyEvent> keyEventHandler =
keyEvent -> {
if (keyEvent.getCode() == KeyCode.TAB) {
Iterator<Node> itr = box.getChildren().iterator();
while(itr.hasNext()) {
if(itr.next() == keyEvent.getSource()) {
if(itr.hasNext()){
itr.next().requestFocus();
}
//If TextArea is the last child
else {
box.getChildren().get(0).requestFocus();
}
break;
}
}
keyEvent.consume();
}
};
textArea.setOnKeyPressed(keyEventHandler);
Scene scene = new Scene(box, 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}