Retrieve inputs from custom DialogBox class - java

I have a Navigator class and a custom DialogBox class which is descended from GridPane.
public DialogBox(final JDialog jdialog) {
Label lblKeyName = new Label("Enter New Key");
Label lblKeyType = new Label("Select Key Type");
TextField txtKeyName = new TextField();
ComboBox cboKeyType = new ComboBox();
txtKeyName.getText();
Button btnOk = new Button("OK");
Button btnCancel = new Button("Cancel");
btnOk.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//TODO: Somehow return the values in the ComboBox and TextField
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
jdialog.setVisible(false);
}
});
txtKeyName.prefWidth(300);
cboKeyType.prefWidth(300);
this.add(lblKeyName, 0, 0);
this.add(lblKeyType, 0, 1);
this.add(txtKeyName, 1, 0);
this.add(cboKeyType, 1, 1);
this.add(btnOk, 0, 2);
this.add(btnCancel, 1, 2);
}
This is the constructor for my DialogBox.
JFXPanel fxPanel = new JFXPanel();
testBox = new DialogBox(jdialog);
fxPanel.setScene(new Scene(testBox));
jdialog.add(fxPanel);
jdialog.setVisible(true);
How can I retrieve the values in the TextField and ComboBox? I can slightly recall a long ago class where the professor mentioned a technique involving the calling class (Navigator in this case) implementing an Interface and then passing itself to the DialogBox class to retrieve values. Unfortunately I have not found anything and cannot remember how it is done.

Assuming that the dialog is modal, basically, once btnOk or btnCancel button is pressed you need to change some kind of state flag which you can interrogate to determine how the dialog was closed...
// This will also handle the use case where the user presses the "x" button...
private boolean wasCancelled = true;
//...
public boolean wasCancelled() {
return wasCancelled;
}
In you action listeners, you need to set the state appropriately.
btnOk.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
wasCancelled = false;
jdialog.setVisible(false);
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
wasCancelled = true;
jdialog.setVisible(false);
}
});
Now, once the dialog returns, you need to check this flag...
jdialog.add(fxPanel);
jdialog.setVisible(true);
if (!jdialog.wasCancelled()) {
//...
}
You then need to supply "getter" methods to allow a caller to extract the values from the dialog...
public String getKey() {
return txtKeyName.getText();
}
public String getType() {
return cboKeyType.getSelectionModel().getValue();
}
This will mean you will need to create these two fields as instance variables

Related

Vaadin add values to list

I would like to have this functionality in my program:
I will have a user input field. When the user pressed the button, it will be added to the list, and input will be shown to the user.
The problem is, I would like to deselect/remove those input if the user wants. I could not achieve this.
Here is the code I have written so far, I have removed some functionality unnecessary for the question's scope:
public class AddUserInput extends VerticalLayout{
// The user input will be added to the this list
// later, this list will be sent to the server for some verification
private List<String> emails;
private HorizontalLayout content;
private VerticalLayout rows;
// user input field
private TextField emailField = new TextField("Enter email address");
public AddUserInput() {
content = new HorizontalLayout();
rows = new VerticalLayout();
content.setMargin(true);
Button addToListButton= new Button("Add to list");
addToListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
// When the user clicks add to list button
// The raw input will be added to the emails list
// The UI component is added to 'rows' component
rows.addComponent(addNewRow(emailField.getValue()));
}
});
content.addComponents(emailField, addToListButton, rows);
addComponent(content);
}
public Component addNewRow(String email){
HorizontalLayout newRow = new HorizontalLayout();
Button deleteRowButton = new Button("-");
deleteRowButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
// I can delete from the UI by using the code below
newRow.removeAllComponents();
rows.removeComponent(newRow);
// How to remove from the email list???
}
});
emails.add(emailField.getValue());
Label lastEmail = new Label(emailField.getValue());
emailField.clear();
newRow.addComponents(lastEmail,deleteRowButton);
return newRow;
}
}
Is there any component/library that does this functionality?
I only need a text field, and adding the input to the list, and removing the list item if a user wants to.
The visualization of the code above:
You could use the NativeSelect component for managing the entered Strings.
I modified your AddUserInput-Component to use a NativeSelect and a corresponding DataProvider:
public class AddUserInput extends VerticalLayout {
private HorizontalLayout content = new HorizontalLayout();;
private NativeSelect<String> select = new NativeSelect<>("The List");
private ListDataProvider<String> dataProvider = DataProvider.ofCollection(new ArrayList<>());
private Button addToListButton= new Button("Add to list");
private Button deleteFromListButton = new Button("-");
private TextField emailField = new TextField("Enter email address");
public AddUserInput() {
select.setVisibleItemCount(5);
select.setWidth("100px");
select.setDataProvider(dataProvider);
select.setEmptySelectionAllowed(false);
deleteFromListButton.setEnabled(false);
content.setMargin(true);
addToListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent event) {
addEmailToList(emailField.getValue());
}
});
deleteFromListButton.addClickListener(new Button.ClickListener() {
#Override
public void buttonClick(Button.ClickEvent clickEvent) {
select.getSelectedItem().ifPresent(selectedItem -> removeSelectedEmailFromList());
}
});
select.addValueChangeListener(new HasValue.ValueChangeListener<String>() {
#Override
public void valueChange(HasValue.ValueChangeEvent<String> valueChangeEvent) {
deleteFromListButton.setEnabled(select.getSelectedItem().isPresent());
}
});
content.addComponents(emailField, addToListButton, select, deleteFromListButton);
addComponent(content);
}
private void addEmailToList(String email){
dataProvider.getItems().add(email);
select.getDataProvider().refreshAll();
emailField.clear();
}
private void removeSelectedEmailFromList(){
select.getSelectedItem().ifPresent(selectedItem -> dataProvider.getItems().remove(selectedItem));
select.setSelectedItem(dataProvider.getItems().isEmpty() ? null : dataProvider.getItems().iterator().next());
select.getDataProvider().refreshAll();
}
}
It looks like the following:
Would that be a possible option for you?

How to know the row of a dynamic created button of a tableview on javafx

I'm currently working on javafx and I have a serious problem. I can't find a way to get the index of the row of a button that I created dynamically on a table view.
If someone could help me out, that would be very helpful.
this.clmColumn.setCellFactory((TableColumn<?, ?> column) -> {
return new TableCell<?, ?>() {
#Override
protected void updateItem(? item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
final HBox hbox = new HBox(5);
final VBox vbox = new VBox(5);
Label label = new Label(item.toString());
final Button btnMais = new Button("+");
btnMais.setMinSize(25, 25);
final TableCell<?, ?> c = this;
btnMais.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// At this point i want to select the current ROW of the button that i pressed on the tableview.
}
});
final Button btnMenos = new Button("-");
btnMenos.setMinSize(25, 25);
btnMenos.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (getItem() > 1) {
// At this point i want to select the current ROW of the button that i pressed on the tableview.
}
}
});
final Button btnRemover = new Button("Remover");
btnRemover.setFont(new Font(8));
btnRemover.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// At this point i want to select the current ROW of the button that i pressed on the tableview.
}
});
vbox.getChildren().add(hbox);
vbox.getChildren().add(btnRemover);
hbox.getChildren().add(btnMais);
hbox.getChildren().add(label);
hbox.getChildren().add(btnMenos);
hbox.setAlignment(Pos.CENTER);
vbox.setAlignment(Pos.CENTER);
setGraphic(vbox);
} else {
setGraphic(null);
}
}
};
});
In the handle() method you can do
Object row = getTableView.getItems().get(getIndex());
You can replace Object with a more specific type if you use more specific types throughout in the type parameters.

How to return result from event handler in javafx?

How to return result from event handler in javafx? I have bellow code, and how to return data from event to function showPrompt? Is it possible to recover the data for the function of the event?
public static String showPrompt(String title, String defValue){
final Stage dlgStage = new Stage();
TextField txtPromptValue = new TextField(defValue);
Button btnOk = new Button("Ok");
Button btnCancel = new Button("Cancel");
btnOk.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
//How to return data from event to function?
dlgStage.close();
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
//How to return data from event to function?
dlgStage.close();
}
});
//
Label lblTitle = new Label(title);
lblTitle.setFont(Font.font("Amble CN", FontWeight.NORMAL, 14));
//
VBox vbox = new VBox(lblTitle,txtPromptValue,btnOk,btnCancel);
vbox.setAlignment(Pos.CENTER);
vbox.setMinSize(300, 200);
//
Scene dlgScene = new Scene(vbox);
//
dlgStage.setScene(dlgScene);
dlgStage.initStyle(StageStyle.UNDECORATED);
dlgStage.initModality(Modality.APPLICATION_MODAL);
dlgStage.setMinWidth(300);
dlgStage.setMinHeight(200);
dlgStage.show();
}
The short answer is you can't return a value.
Why ?
This code bellow is called a callback.
new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
dlgStage.close();
}
}
Callbacks have no return type, as you can see in the example above, it is void.
Callbacks are methods that you pass as an argument to another method. The other method will call you callback method when it wants. This means that callbacks are asynchronous. In your example, it calls the callback when you press the button.
In conclusion, you can't return from it using return.
What to do ?
You can call a method from your callback and sent your return value to it as an argument.
Example:
btnCancel.setOnAction(
new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
YourClass.setReturnValue("This is button Cancel");
dlgStage.close();
}
}
});
Where setReturnValue is a method belonging to YourClass or an instance of it so it will retail your returned value.
Another way better approach would be to create a class that extends Stage maybe. Also in your showPrompt method you will have to block execution using showAndWait() or similar.
In conclusion, you can't create your entire Prompt from just one method.
You can't, because by the time you've opened and closed the prompt stage, the main thread will have already passed the showPrompt method.
As Andrei said, what you need to do is create your own custom PromptStage with a showPrompt API that blocks the main thread until the prompt stage is closed.
public static String showPrompt(final String title, final String defValue)
{
// This line will block the main thread
// See the "showAndWait()" API from JavaFX
final boolean result = PromptStage.showPrompt("My Prompt Stage", " ");
// And when the stage is closed, it will carry on to this piece of code
if (result)
{
return "This is button OK";
}
else
{
return "This is button CANCEL";
}
}
Or you could even create instances of your PromptDialog if you like
public static String showPrompt(final String title, final String defValue)
{
final PromptStage pStage = new PromptStage();
// This line will block the main thread
// See the "showAndWait()" API from JavaFX
pStage.showAndWait();
return pStage.getResultAsString();
}
There are very many approaches here. To be honest, I won't bother writing the whole class for you. However, do comment if you're stuck.
Another option is to pass the showPrompt(...) method a StringProperty, and update the property in your OK button's handler. The caller of showPrompt can then create the StringProperty, register a listener with it, and observe it. Something like:
public String showPrompt(String title, String defValue, final StringProperty result){
// ...
final TextField txtPromptValue = new TextField(defValue);
// ...
btnOk.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
result.set(txtPromptValue.getText());
dlgStage.close();
}
});
// ...
}
Then you call the dialog with something like:
StringProperty dialogResult = new SimpleStringProperty();
dialogResult.addListener(new ChangeListener<String>() {
public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) {
// process newValue, the value from the dialog...
}
});
showPrompt("Dialog Title", "Default value", dialogResult);

key-bindings and holding down keys

I have created a key binding for a JTextArea Component. When invoked, it creates a new instance of itself and sets focus to it.
If you hold down the enter (which invokes key binding) my program will start spitting out bunch of JTextArea instances.
Is there a way to force the user to press enter againg to create a new instance?
Do I have I switch to KeyListeners or is there a way with key bindings?
You specify that a KeyStroke only fire on key release when you're setting up the input map
See KeyStroke getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
the way to do it with keybindings is to have two actions:
an action creating the component is bound to the pressed enter, it disables itself when inserting the component
an action enabling the action again is bound to the released enter
Some code:
// the action to create the component
public static class CreateAction extends AbstractAction {
private Container parent;
private Action enableAction;
public CreateAction(Container parent) {
this.parent = parent;
enableAction = new EnableAction(this);
}
#Override
public void actionPerformed(ActionEvent e) {
setEnabled(false);
Component field = createTextField();
parent.add(field);
parent.revalidate();
field.requestFocus();
}
int count;
private Component createTextField() {
// just for fun counting the fields we create
JTextField field = new JTextField("field: " + count++, 20);
field.getInputMap().put(KeyStroke.getKeyStroke("ENTER"),
"createComponent");
field.getActionMap().put("createComponent", this);
field.getInputMap().put(KeyStroke.getKeyStroke("released ENTER"),
"enableCreation");
field.getActionMap().put("enableCreation", enableAction);
return field;
}
}
// the action that enables another
public static class EnableAction extends AbstractAction {
Action toEnable;
public EnableAction(Action toEnable) {
this.toEnable = toEnable;
}
#Override
public void actionPerformed(ActionEvent e) {
toEnable.setEnabled(true);
}
}
// usage
final JComponent parent = new JPanel(new MigLayout("wrap"));
// here I'm lazy and let the action create the very first component as well
add.actionPerformed(null);
add.setEnabled(true);
Note that the same instances of the actions are registered to all components, so it doesn't matter which has the focus (and ultimately enables the creation again)
Here is the code I use, to have an action only run when a key is first pressed down:
private void registerKeyBindings(final JFrame frame) {
var inputMap = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, false), "g_down");
inputMap.put(KeyStroke.getKeyStroke(KeyCode.G.getInputEventCode(), 0, true), "g_up");
frame.getRootPane().getActionMap().put("g_down", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
if (gDown) return;
gDown = true;
// put your custom key-down-action code here
}
});
frame.getRootPane().getActionMap().put("g_up", new AbstractAction() {
#Override public void actionPerformed(ActionEvent e) {
gDown = false;
}
});
}
Boolean gDown = false;

Method chose based on variable value

I'm writing a user's GUI and I want to create a method that will be create various number of buttons with previously defined names and actions. But I have no idea how to write method selection which is based on variable value. Google gives no useful information about it. Can anyone help with this or it's just impossible?
Here is some code example:
String[] actions={"testAction1","testAction2","testAction3"};
defaultDialogWindow(actions,"test1", "test2", "test3");
void defaultDialogWindow(String[] actions, String... bNames){
double layoutX = 25;
double spacing = 15;
final Stage dialogStage = new Stage();
dialogStage.initOwner(stage);
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.setFullScreen(false);
dialogStage.setResizable(false);
dialogStage.setHeight(100);
dialogStage.setWidth(bNames.length*100+(bNames.length-1)*spacing+2*layoutX+5);
dialogStage.setScene(new Scene(buttonBuilder(actions,spacing,layoutX,bNames)));
dialogStage.show();
}
HBox buttonBuilder(String[] actions, double spacing,double layoutX,String... bNames){
HBox lBar = new HBox(10);
final ReadOnlyDoubleProperty menuWidthProperty = lBar.widthProperty();
lBar.setAlignment(Pos.CENTER_LEFT);
lBar.setLayoutX(layoutX);
lBar.setSpacing(spacing);
for(String text : bNames){
Button newButton = new Button();
newButton.setText(text);
newButton.setFont(Font.font("Times New Roman", 22));
newButton.prefWidthProperty().set(100);
newButton.prefHeightProperty().set(50);
newButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent paramT) {
**HERE MUST BE ACTION CALL BASED ON bNames VALUE**
System.out.println("button pressed");
}
});
lBar.getChildren().add(newButton);
}
System.out.println(lBar.prefWidth(-1));
return lBar;
}
void testAction1(){
System.out.println("this is test action one");
}
void testAction2(){
System.out.println("this is test action two");
}
void testAction3(){
System.out.println("this is test action three");
}**strong text**
Use HashMap:
Map<String, Runnable> actions2methods = new HashMap<>;
actions2methods.put("Action1", new Runnable { public void run() { testAction1(); }));
You can even make this easier if your actions would be Runnable instead of methods from the start.
You can use the actionCommand property of the ActionEvent to communicate which action was taken. This defaults to the label of the button but can also be set (without affecting the label) using Button.setActionCommand().
newButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent paramT) {
String actionCmd = paramT.getActionCommand();
if (actionCmd.equals("A")) {
doA();
} else if (actionCmd.equals("B")) {
doB();
}
System.out.println("button pressed");
}
});
http://docs.oracle.com/javase/6/docs/api/java/awt/Button.html#setActionCommand%28java.lang.String%29
http://docs.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html

Categories

Resources