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
Related
how can I refactor the following code so that only the code in deleteButton.setOnAction(deleteEvent -> {//only this code varies} changes. Everything else will stay the same but the block of code in the lambda expression varies from time to time when I call the class from another class. The block of code that goes through the lambda expression is supposed to be a void method.
public class A {
public void test() {
// ensure that user can't close the alert
Stage primaryStage = (Stage) RootLayoutController.getRootLayout().getScene().getWindow();
JFXAlert<javafx.scene.control.ButtonType> alert = new JFXAlert<>(primaryStage);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setOverlayClose(false);
//create font awesome icon
String ICON = "\uf071";
Label labelIcon = new Label(ICON);
labelIcon.setStyle("-fx-font-family: 'FontAwesome'; -fx-font-size: 60px; -fx-text-fill: #D34336;");
labelIcon.setPadding(new Insets(0,5,0,0));
// Create the content of the JFXAlert with JFXDialogLayout
JFXDialogLayout layout = new JFXDialogLayout();
Label labelHeading = new Label("Alert Notification");
Label labelBody = new Label("Are you sure you want to delete this?");
layout.setHeading(labelHeading);
layout.setBody(new VBox(new HBox(labelIcon, labelBody)));
// Buttons get added into the actions section of the layout.
JFXButton deleteButton = new JFXButton("Delete");
deleteButton.setDefaultButton(true);
deleteButton.setOnAction(deleteEvent -> {
//only this block of code changes
alert.hideWithAnimation();
});
JFXButton cancelButton = new JFXButton("Cancel");
cancelButton.setCancelButton(true);
cancelButton.setOnAction(closeEvent -> alert.hideWithAnimation());
layout.setActions(deleteButton, cancelButton);
alert.setContent(layout);
alert.showAndWait();
}
}
It is not entirely clear from your question what you are trying to accomplish, but I will take a wild stab at it.
If you are looking to be able to pass a code block to the deleteButton.setOnAction() method, you could use an Interface and pass implementations of that interface to the A class. Then just pass that reference to an internal method for the onAction lambda.
Here is a very quick example of how you could do something like this:
Main.java:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Action button
Button btnDoSomething = new Button("Do something...");
btnDoSomething.setOnAction(e -> doTheThings(new ImplDoSomething()));
Button btnDoSomethingElse = new Button("Do something else...");
btnDoSomethingElse.setOnAction(e -> doTheThings(new ImplDoSomethingElse()));
VBox mainPane = new VBox(5);
mainPane.setAlignment(Pos.CENTER);
mainPane.setPadding(new Insets(10));
mainPane.getChildren().addAll(btnDoSomething, btnDoSomethingElse);
primaryStage.setScene(new Scene(mainPane));
primaryStage.show();
}
private void doTheThings(IParameterMethod parameterMethod) {
parameterMethod.call();
}
}
The IParameterMethod.java Interface:
public interface IParameterMethod {
void call();
}
Then you can create as many classes as you like that implement that interface, each with their own call() method, allowing you to execute different code.
ImplDoSomething.java
public class ImplDoSomething implements IParameterMethod {
#Override
public void call() {
System.out.println("Doing something!");
}
}
ImplDoSomethingElse.java:
public class ImplDoSomethingElse implements IParameterMethod {
#Override
public void call() {
System.out.println("Doing something else!");
}
}
This should be easily adapted for your project.
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);
I have a JComboBox which uses GlazedLists to add type-ahead functionality. I want the user to type in a string and see type-ahead (this is working thanks to Glazedlists). However, I don't want users to be able to click the down arrow of the combobox and inspect the dropdown list. I've made the down arrow invisible and made the combobox editable so that it resembles a JTextField. However, you are still able to hover the mouse over the area where the down arrow used to be and click it. This results in the dropdown appearing. What do I change or which methods do I override in order to remove the 'click and get dropdown' functionality.
ComboBox<String> box = new ComboBox<String>();
box.setEditable(true);
box.setUI(new BasicComboBoxUI(){ // make the down arrow invisible
protected JButton createArrowButton() {
return new JButton() {
public int getWidth() {
return 0;
}
};
}
});
SwingUtilities.invokeLater(new Runnable(){
public void run(){
Object[] elements = new Object[] {"java", "perl", "python", "haskell", "erlang", "groovy"};
AutoCompleteSupport.install(box, GlazedLists.eventListOf(elements));
}
});
Override JButton#addMouseListener:
JComboBox<String> box = new JComboBox<>();
box.setEditable(true);
box.setUI(new BasicComboBoxUI() { // make the down arrow invisible
protected JButton createArrowButton() {
return new JButton() {
public int getWidth() {
return 0;
}
#Override
public synchronized void addMouseListener(MouseListener l) {
}
};
}
});
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
I have a JLabel that has keybinded actions on it. I have defined some code for some of the Actions but, alas, there are other JLabels, a JPanel, and other things within the method (this is in main()) that I want my Actions to fool with.
I tried to change the Actions into taking parameters, but was not successful, how can I get my actions to take in parameters to manipulate? Is there any way? I have looked about but this is pretty specific and I see few good examples.
Here is a nice slab of my code:
/*Bunch of stuff I want my actions to interact with above - another JLabel, a JPanel*/
ImageIcon cursor = new ImageIcon("cursor.gif");
JLabel cursorlbl = new JLabel("", cursor, JLabel.CENTER);
Action goRight = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("lol");
}
};
Action goLeft = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("lol2");
}
};
Action goUp = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
}
};
Action goDown = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("lol2");
}
};
cursorlbl.setFocusable(true);
cursorlbl.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"),
"pressed right");
cursorlbl.getInputMap().put(KeyStroke.getKeyStroke("LEFT"),
"pressed left");
cursorlbl.getActionMap().put("pressed right", goRight);
cursorlbl.getActionMap().put("pressed left", goLeft);
You can declare each action as a subclass (this starts to separate MVC anyways), and each item you want to manipulate a field in the parent class. Example:
// Parent Class
public class ParentClass{
//Field you want to mess with in your action
JLabel cursorlbl = new JLabel("");
// Action that does things
public class MoveAction extends AbstractAction{
char direction;
//Constructor for action
public MoveAction(char direction){
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent arg0) {
int change = 0;
// Figure out how you'll be changing the variable
if(direction == 'u' || direction == 'r'){
change = 1;
} else{
change = -1;
}
// Apply the change to the correct variable
if(direction == 'u' || direction =='d'){
cursy += change;
} else{
cursx += change;
}
//Example how you can access the parent class's fields
cursorlbl.setLocation(cursx, cursy);
}
}
}
Then to set your actions, you just create instances of your subclass:
contentArea.getActionMap().put("pressed right", new MoveAction('r'));
contentArea.getActionMap().put("pressed left", new MoveAction('l'));
Declare other components you wish to see in your actions as final. That will make actions see them.
More info here
You should be able to pass them in like this:
// note that the JLabel is now final
final JLabel cursorlbl = new JLabel("", cursor, JLabel.CENTER);
Action goRight = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(cursorlbl.getText()); // has access to JLabel because it's scoped to the method/class
}
};
Note that doing this can cause some maintenance issues and you should try to document things that might be unclear for future developers (and yourself two weeks from now!)