GWT - stockwatch example - event handling explanation - java

First of all, hi everyone. I'm new here and i just have started learning gwt. There is one thing that i dont understand regarding stockwatch example. First of all, there is add stock method, which adds new stock to a list. Inside that method we also add remove button and attach listener to it. My question is, how is it possible that indexOf attr is set, when u dont enter that part of code when u add new stock, u only enter that part when u click remove button. But this code works, and i cant find explanation why..I tried to debug app, but still having trouble to undestand. Sorry for my bad english.
private void addStock()
{
final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
//validaciju vrsimo upotrebom regularnih izraza
if(symbol.matches("[0-9A-Z]"))
{
Window.alert("'" + symbol + "' is not a valid symbol.");
newSymbolTextBox.selectAll();
return;
}
newSymbolTextBox.setText("");
if(stocks.contains(symbol))
{
return;
}
int row = stocksFlexTable.getRowCount();
stocks.add(symbol);
stocksFlexTable.setText(row, 0, symbol);
Button removeStockButton = new Button("x");
removeStockButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
int indexOf = stocks.indexOf(symbol);
stocks.remove(indexOf);
stocksFlexTable.removeRow(indexOf + 1);
}
});
stocksFlexTable.setWidget(row, 3, removeStockButton);
refreshWatchList();
}

My question is, how is it possible that indexOf attr is set, when u
dont enter that part of code when u add new stock, u only enter that
part when u click remove button.
Read about anonymous inner classes as event listeners. new ClickHandler() provides a handler to each Button, which catches the click event, with the functionality that will remove the line, whenever the specific delete button is pressed. Every button has it's own clickHandler.
indexOf is not a great name for a variable. I would rather stick to removedIndex, used in the www.gwtproject.org sample code:
// Add a button to remove this stock from the table.
Button removeStockButton = new Button("x");
removeStockButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
int removedIndex = stocks.indexOf(symbol);
stocks.remove(removedIndex);
stocksFlexTable.removeRow(removedIndex + 1);
}
});
stocksFlexTable.setWidget(row, 3, removeStockButton);

Related

Java int can't be changed because lambda expression must be final or effectively final

I am trying to make a Java tic tac toe game and am having some issues with the code.
What I want to do is just increment an int when the user clicks a button.
The problem is is that the compiler says "Error:local variables referenced from a lambda expression must be final or effectively final". What I understand this to mean is that I can only create an value and not redefine it in the same method but I am new to java and have no idea for a work around.
I am thinking of a work around by having multiple classes but this is overly complicated and I just want to add to the int like in python. If anyone has any idea on how to do this or a work around then it would be greatly appreciated.
Below is my program
public class TicTacToe extends Application {
#Override
public void start(Stage primaryStage) {
//Some code here
//this is Cerateing all the buttons
//the buttons are formated in a 3X3 array for a total of 9 buttons
Button B1 = new Button();
//More buttons
//this sets the size of the button
//this is the int that tracks what button the user has pressed
//this is my value
int User = 0;
//this gets if the user has clicked any of the buttons shold in therory do somthing
B1.setOnAction((event) -> {
B1.setText("X");
//this is where I want to add to an value
User++;
});
//More code
System.out.println(User);
}
}
You didn't specify where you got error, but this part should give an error:
int User = 0;
B1.setOnAction((event) -> {
B1.setText("X");
User++;
});
The User variable either needs to be a field, a wrapper like AtomicInteger or new int[1], or a final object. Here are a couple of ways to get around this. First of all, you can just make User a field.
private int User = 0;
Then don't declare it in the method. Another thing you can do is make a new int[1].
int User = new int[]{0};
B1.setOnAction((event) -> {
B1.setText("X");
User[0] ++;
});
Then when accessing it, you can use User[0]. Another way is using AtomicInteger. I don't really like it that much, but here is how you can use it anyways:
AtomicInteger User = new AtomicInteger(0);
B1.setOnAction((event) -> {
B1.setText("X");
User.incrementAndGet();
});

Passing information to JavaFX Button handle() routine

I have the following code to set up a Button in JavaFX 8:
Button button = new Button("target name");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Button pressed = (Button)event.getSource();
// next target name is the title of the button
handleClick(pressed.getText());
}
});
I would like to pass some information to the handleClick() routine. In this case I have a String that is a "target name" and handleClick() is a method that knows what to do with that. Right now I'm passing that information by making it the name of the Button. Is there a better way? For instance, what if I wanted to pass two pieces of information? Or, what if the info I want to pass is not a String?
The handle() routine only accepts an ActionEvent parameter. I can't find anything in ActionEvent that would help me here.
One idea I had: Maybe I could write my own SmartButton subclass that extends Button, and include in that subclass some additional info that is passed in at the time the SmartButton is constructed (so in the subclass I would only implement an extra constructor and one or more new getters/setters). The handleClick() routine would then have access to that information via getters called on (SmartButton)event.getSource().
This seems like a common UI programming issue. What is the best practice?
Thanks.
In the code snippet you posted, the event handler is only associated with the button created in the first line. Furthermore, since it's an anonymous inner class you know you only have the one instance of that class, and consequently that event handler cannot be associated with any other control. So your code is completely equivalent to
Button button = new Button("target name");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
handleClick(button.getText());
}
});
or, using lambda expressions:
Button button = new Button("target name");
button.setOnAction(event -> handleClick(button.getText()));
You can basically always do this, even if the data needed to handle the button press is not the text in the button. Consider a calculator app (restrict it to integers for simplicity). You would likely have some variable storing the current value displayed:
private int value ;
and then you want a bunch of numeric buttons which "append" their own value to the current value (so if the current value is 1 and you press "2", the current value should be 12, etc):
You would just need
for (int i = 0 ; i <= 9 ; i++) {
Button button = createButton(i);
// place button in UI...
}
with
private Button createButton(int buttonValue) {
Button button = new Button(Integer.toString(buttonValue));
button.setOnAction(e -> value = value * 10 + buttonValue);
return button ;
}
Some variation on this idea will always give you what you need.

JavaFX Dialog returns same result over and over again

Solved: I figured that it isn't a bug of JavaFX, it is made like that on purpose, so you can request the result multiple times from the dialog if you don't wanna save it into a variable. To flush the cache i used setResult(null) on the dialog. That did the job for me :)
I've created a Dialog to edit/create a Person using JavaFX. But i guess i found a bug. I've added two ButtonType-objects to my dialog. One for saving and one for aborting the actions. When i use those buttons it works just fine. But if i press the 'X' to close the dialog-window, the dialog automaticly returns the last result again. That means if i aborted my last action and in my current one i press 'X' to close the window, the dialog returns no result since the abort-button didn't have one last time. But if i pressed the save-button on my last action and i press 'X' in my current one it returns the same person again, since save-button had this person in its result last time. How can i make the dialog changing to no result on closing?
Here is the action i've created:
this.createPersonAction = new Callback<ButtonType, PersonSession>() {
#Override
public PersonSession call(final ButtonType param) {
if (param.equals(PersonDialogController.this.saveButton)) {
final String firstName = PersonDialogController.this.firstNameField.getText();
final String lastName = PersonDialogController.this.lastNameField.getText();
final Person p = BeanFactory.createPerson(firstName, lastName);
if (p != null) {
return new PersonSession(p);
}
}
return null;
}
};
And here you have my two ButtonType-Objects:
private final ButtonType saveButton = new ButtonType(GuiStringRresource.LABEL_SAVE_BUTTON, ButtonData.OK_DONE);
private final ButtonType abortButton = new ButtonType(GuiStringRresource.LABEL_ABORT_BUTTON,
ButtonData.CANCEL_CLOSE);
Use the Dialog.setOnCloseRequest method to handle this case.

For a GWT java FlexTable how do I get the selected row number on value change

I want to store the GWT FlexTable row number that contains a date when that date is changed. The code is:
//Add change handler for the task completion date.
dateCompletion.addValueChangeHandler(new ValueChangeHandler<java.util.Date>() {
public void onValueChange(ValueChangeEvent<java.util.Date> event) {
//TODO currentRow = flexAwardDescription.getRowIndex();
//Display all YM who have not completed this task.
AsyncCallback<List<YouthMember>> callback = new YMWithoutAwardHandler<List<YouthMember>>(CubBulkAward3View.this);
rpc.getYMWithoutAwardList(ymAwardDetails.getad_Id(), callback);
}
});
I have found an answer for click event; however, not for change event.
Please check my answer here: Gwt getCellForEvent flexTable
There's no obvious way to do it, what you can do is
Get event source
Cast it to widget
Get it's Element via .getElement() then use getParent() to get Cell, and getParent() one more time to get row element.
You can get it's index then, comparing it to rows from rowFormatter in a loop.
The work around I came up with is to capture row number on the click event (as you must first click before you can change) and then use this row number if a change event occurs.
//Get the row number of the row selected to display the names below it.
flexAwardDescription.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
currentRow = flexAwardDescription.getCellForEvent(event).getRowIndex();
}
});
//Add change handler for the task completion date.
dateCompletion.addValueChangeHandler(new ValueChangeHandler<java.util.Date>() {
public void onValueChange(ValueChangeEvent<java.util.Date> event) {
//Check if this is the completion row
if (ymAwardDetails.getad_Description().matches("(.*)Completed:(.*)")) {
groupCompleted = "C";
}else{
groupCompleted = "S";
}
awardDescriptionID = ymAwardDetails.getad_Id();
//Display all YM who have not completed this task.
AsyncCallback<List<YouthMember>> callback = new YMWithoutAwardHandler<List<YouthMember>>(CubBulkAward3View.this);
rpc.getYMWithoutAwardList(ymAwardDetails.getad_Id(), accountId, callback);
}
});

Java/JavaFX2: dynamic GUI, detect which button was pressed, extract id

I'm a newbie in Java/JavaFX (I began yesterday evening). I'm building a dynamic GUI (crud) reading off a MySQL database.
I managed to display the data in a table and add a button next to each row.
Since the number of buttons is variable, I want to define only a common eventhandler.
The problem is that whenever I use event.getSource() (it's an ActionEvent) and display it, I get something like "Button[id=0, styleClass=button].
Question 1: Is there any way I could put the id in a variable? I can't get it out of the object.
As far as I know, I have to use the id, since I can't do something like this "if(event.getSource() == somebutton) {...}" since every generated button had the same variable name.
Now, this is the loop (inside a method called make_buttons) that builds the buttons. n_buttons is the number of buttons I want to build.
for(int counter = 0; counter < n_buttons; counter++){
String newtext = new String("btn"+counter);
Button btn = new Button();
btn.setText(newtext);
btn.setId(Integer.toString(counter));
btn.setOnAction(myHandler);
grid.add(btn,0,counter);
}
Note that I'm placing the buttons on a gridpane one on top of the other.
Before that part I have my handler:
final EventHandler<ActionEvent> myHandler = new EventHandler<ActionEvent>(){
public void handle(final ActionEvent event) {
Object new_output = event.getSource();
System.out.println(new_output);
event.consume();
}
};
Question 2: so, how can I differentiate which button fired the event in my particular case?
I know quite a few programming languages (Matlab, R, Python, C, Assembly, etc... but I'm a hobbyist), but it's the first time I'm working with GUI elements (except web languages and ActionScript 3).
In actionscript I could just do something like event.getCurrentTarget and the use it exactly as if it were the object itself to read the id, properties, etc.
I looked everywhere and couldn't find anything (maybe my terminology was a bit approximative...).
If I understand your question correcty, you can simply access the clicked button in you handle method with the following code:
Object source = event.getSource();
if (source instanceof Button) { //should always be true in your example
Button clickedBtn = (Button) source; // that's the button that was clicked
System.out.println(clickedBtn.getId()); // prints the id of the button
}

Categories