Sending Textfield input on ButtonClick or Enter Key - java

I'm trying to make a Chat, so that when I press enter or press the 'Send' Button, the input of the Textfield will go into a ListView. And it does it's job, although the code is really messy.
My controller code is as following:
public void initialize() {
sendButton.setDisable(true);
}
public void isChatEmpty() {
boolean isChatEmpty = textInput.getText().isEmpty();
sendButton.setDisable(isChatEmpty);
}
public void sendMessageOnClick(){
sendButton.setOnAction((e) -> {
String message = textInput.getText();
chatHistory.getItems().add("Sorin: " + message + "\n");
textInput.setText(null);
sendButton.setDisable(true);
});
}
public void sendMessageOnEnter(){
textInput.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ENTER) {
String message = textInput.getText();
chatHistory.getItems().add("Sorin: " + message + "\n");
textInput.setText(null);
sendButton.setDisable(true);
System.out.print("test");
}
});
}
I know it works because I can see it in the GUI, but I somehow, get a Nullpointer on my 'isChatEmpty', which to be fair, I do not know why.
Caused by: java.lang.NullPointerException
at sample.Controller.isChatEmpty(Controller.java:29)
Also, is there a way to combine the two Lambdas functions?
Thank you in advance!

In case of enter and click there is an easy way to deal with this: Use the onAction method for both. For TextField this is triggered when you press enter. Furthermore those handlers should be assigned from fxml. Also use binding to disable the button:
<TextField fx:id="textInput" onAction="#send"/>
<Button fx:id="sendButton" text="Send" onAction="#send"/>
#FXML
private void initialize() {
sendButton.disableProperty().bind(textInput.textProperty().isEmpty());
}
#FXML
private void send() {
String message = textInput.getText();
if (message != null && !message.isEmpty()) {
chatHistory.getItems().add("Sorin: " + message);
textInput.clear();
}
}

In isChatEmpty() method the result of textInput.getText() is null as you set it with textInput.setText(null);.
This null causes NPE (see docs for String.isEmpty()).
To resolve this you can remove isChatEmpty() method and setup unidirectional binding:
public void initialize() {
sendButton.disableProperty().bind(textInput.textProperty().isEmpty());
}
Note the .isEmpty() here is not a call to String.isEmpty() but to
StringExpression.isEmpty() what generates binding of type BooleanBinding.

Related

How to let TextFieldTableCell handle focus loss as commit instead of cancellation?

The default behavior of a TextFieldTableCell in JavaFX is:
Hit ENTER: commit the edit,
Hit ESC: cancel the edit,
Focus is lost: cancel the edit.
The cancellation of the edit when focus is lost is very unnatural, and causes my users to lose data.
I already tried to create an alternative implementation of TextFieldTableCell, where I added a listener on the textfield.focusedProperty() to force a commit, but this doesn't work well at all.
Does anyone have a suggestion on how this behavior can be improved?
My adapted createTextField-function:
private static <T> TextField createTextField(final Cell<T> cell, final StringConverter<T> converter) {
final TextField textField = new TextField(getItemText(cell, converter));
// Use onAction here rather than onKeyReleased (with check for Enter),
// as otherwise we encounter RT-34685
textField.setOnAction(event -> {
if (converter == null) {
throw new IllegalStateException(
"Attempting to convert text input into Object, but provided "
+ "StringConverter is null. Be sure to set a StringConverter "
+ "in your cell factory.");
}
cell.commitEdit(converter.fromString(textField.getText()));
event.consume();
});
textField.setOnKeyReleased(t -> {
if (t.getCode() == KeyCode.ESCAPE) {
cell.cancelEdit();
t.consume();
}
});
textField.focusedProperty().addListener(observable -> {
if (!textField.isFocused()) {
cell.commitEdit(converter.fromString(textField.getText()));
}
});
return textField;
}

JavaFX - Accelerator not working when textfield has focus

In my application I have a screen where I use Accelerators. I'm using the function key F3 to execute an operation in my application. It works fine everytime, but when I click in any TextField on this screen the function key doesn't execute.
Here is the code where I set the Accelerator:
scene.getAccelerators().put(
new KeyCodeCombination(KeyCode.F3),
new Runnable() {
#Override
public void run() {
// do sth here
}
}
);
When I click my textfield and then hit the F3 function key it doesn't work.
Someone knows the solution?
This works for me using Java 1.8.0_45. However I encounter a similar issue with an editable Combobox field.
Edited:
Upon further investigation it does seem to occur with text field as well. I worked around it using the following custom class in place of text field:
public class ShortcutFriendlyTextField extends TextField{
public ShortcutFriendlyTextField() {
super();
addEventHandler(KeyEvent.KEY_RELEASED,new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
//handle shortcuts if defined
Runnable r=getScene().getAccelerators().get(new KeyCodeCombination(event.getCode()));
if(r!=null) {
r.run();
}
}
});
}
}
This answer is based on tikerman's. I added the code to handle modifier keys.
if (!event.getCode().isModifierKey()) {
Consumer<KeyCombination.Modifier[]> runAccelerator = (modifiers) -> {
Runnable r = getScene().getAccelerators().get(new KeyCodeCombination(event.getCode(), modifiers));
if (r != null) {
r.run();
}
};
List<KeyCombination.Modifier> modifiers = new ArrayList<>();
if (event.isControlDown()) modifiers.add(KeyCodeCombination.CONTROL_DOWN);
if (event.isShiftDown()) modifiers.add(KeyCodeCombination.SHIFT_DOWN);
if (event.isAltDown()) modifiers.add(KeyCodeCombination.ALT_DOWN);
runAccelerator.apply(modifiers.toArray(new KeyCombination.Modifier[modifiers.size()]));
}
Edit: fix consumer spelling.
If you have accelerators setup else where, such as a MenuBar, using some of the other solutions will cause the shortcut to be executed twice.
In my case, using modifiers with my shortcut (SHIFT + F3) works while in focus in the text area, but not while using just an accelerator such as just F3.
I set mine up to only use the event handler for shortcuts that do not use a modifier.
public static final double JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version"));
public static void makeInputFieldShortCutFriendly(Node node) {
//this bug wasn't fixed until 9.0
if (JAVA_VERSION < 9) {
node.addEventHandler(KeyEvent.KEY_RELEASED, (KeyEvent event) -> {
if (!event.getCode().isModifierKey()) {
if (!event.isAltDown() && !event.isShiftDown() && !event.isAltDown()) {
Runnable r = node.getScene().getAccelerators().get(new KeyCodeCombination(event.getCode(), KeyCodeCombination.SHORTCUT_ANY));
if (r != null) {
r.run();
}
}
}
});
}
}
Edit: No modifier shortcuts was fixed in Java 9. Given the popularity of JDK 8 right now, we should probably provide some backwards capatability or request users update there JRE to 9+.
I you are using JavaFx+Scene builder then just make a function that redirect all the event to the respective functions and then add this function to every element in the scene with OnKeyReleased event

Tapestry5 zone doesn't update on radio button change using zoneUpdater

I've got 2 radio buttons on my Tapestry5 page and I want to update zone when value changes:
<t:radio t:id="allDay" t:mixins="zoneUpdater" t:event="allDayChanged" t:clientEvent="change" zone="timeRecZone"/>
<t:radio t:id="timeRestricted" t:mixins="zoneUpdater" t:event="timeRestrictedChanged" t:clientEvent="change" zone="timeRecZone"/>
<t:zone t:update="show" elementName="div" t:id="timeRecZone" id="timeRecZone">
<t:if test="timeRestrictedSelected">
.
.
.
I'm using known zoneUpdater mixin which works fine for me with textfield at other place of my page. But here, I don't really see timeRecZone get updated, because area under the IF condition is not being shown and I don't see following statement being logged when I'm clicking radios.
public boolean isTimeRestrictedSelected() {
log.info("***** isTimeRestrictedSelected...");
return selectedTimeRestriction == TimeRestriction.TIME_RESTRICTED;
}
This part (change event) works though:
public void onAllDayChanged() {
selectedTimeRestriction = TimeRestriction.ALL_DAY;
log.info("***** allDayChanged called: " + selectedTimeRestriction);
}
public void onTimeRestrictedChanged() {
selectedTimeRestriction = TimeRestriction.TIME_RESTRICTED;
log.info("***** timeRestrictedChanged called: " + selectedTimeRestriction);
}
Has anybody experienced this while working with radio/zone update? Many thanks.
Mea culpa, solution is here:
public void onAllDayChanged() {
selectedTimeRestriction = TimeRestriction.ALL_DAY;
ajaxResponseRenderer.addRender("timeRecZone", timeRecZone);
}
public void onTimeRestrictedChanged() {
selectedTimeRestriction = TimeRestriction.TIME_RESTRICTED;
ajaxResponseRenderer.addRender("timeRecZone", timeRecZone);
}

zk: after confirmation box, page refresh issue, binder not working

I was successfully deleting selected items from listbox and after that all objects were deleted from db and listbox was refreshed.
then i added the confirmation box with yes and no option, then my list wasn't refreshed. i saw this thread with similar problem on zk forum with a solution, i implemented it but getting the class cast exception
I am using MVVM
http://forum.zkoss.org/question/73640/refreshing-listbox-after-deleting-an-itemrow/
code getting the exception:
AnnotateDataBinder binder = (AnnotateDataBinder) userWin.getAttribute("binder");
binder.loadAll();
exception:
Mar 21, 2013 5:22:23 PM org.zkoss.zk.ui.impl.UiEngineImpl handleError:1352
SEVERE: >>java.lang.ClassCastException: org.zkoss.bind.AnnotateBinder cannot be cast to org.zkoss.zkplus.databind.AnnotateDataBinder
looking forward to hear from you. I have searched the net, but couldn't find anything but updating the zk. i am already using the latest version of zk 6.5.1.1.
thanks in advance.
#after adding your suggested line of code, my list was not updated, here is my method
#Override
#Command("deleteAllSelected")
#NotifyChange({"selectedObject","objectList"})
public void deleteAllSelected() {
logger.info("in deleteAllSelected()>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
logger.info("direct selection: " + objectList.getSelection());
final Set<UserIntelliopsDTO> setMe = objectList.getSelection();
logger.info("selectedion size in dellete all" + setMe.size());
EventListener<ClickEvent> clickListener = new EventListener<Messagebox.ClickEvent>() {
public void onEvent(ClickEvent event) throws Exception {
if (Messagebox.Button.YES.equals(event.getButton())) {
int i =0;
for(UserIntelliopsDTO dto:setMe){
userService.deleteUserIntelliops(dto.getUserIntelliOps().getUserId());
logger.info("siapa:userIntelliops " + dto.getUserIntelliOps() + dto.getUserIntelliOps().getUserId());
selectedObject = null;
logger.info("iteration: " + i);
++i;
}
selectedObject = null;
deleteAllSelectedButton.setVisible(false);
enableEditMode(true);
}
}
};
Messagebox.show("Are you sure you want to delete all selected records?", "Delete All Selected",
new Messagebox.Button[] { Messagebox.Button.YES,
Messagebox.Button.NO }, Messagebox.QUESTION,
clickListener);
BindUtils.postNotifyChange(null, null, this, "*");
}
I am assuming you are using MVVM Model..So you can do this thing when you will click on delete button below method will code...
#Command
public void doDeleteItems(#ContextParam(ContextType.VIEW) Component view) {
logger.debug("Delete Icon selected");
if (myModel.getSelectedListItem() == null || myModel.getSelectedListItem().isEmpty()) {
showError("No rows are selected");
} else {
Messagebox.show("Are you sure you want to delete?", "Alert !!", Messagebox.YES | Messagebox.NO, Messagebox.QUESTION,new org.zkoss.zk.ui.event.EventListener() {
public void onEvent(Event evt) throws InterruptedException {
if (evt.getName().equals("onYes")) {
//Add code for Deletion
if (listModel.contains(deletedObj))
listModel.remove(deletedObj);
}
else{
//Do somthing else
}
BindUtils.postNotifyChange(null, null, this, "*");//this means current viewmodel object and refresh the variables
}
As i did BindUtils.postNotifyChange() it will do magic for you refreshing the list or you can use NotifyChange("*")
One more thing you have to do here remove object from list after deleting the record...

Disable back button in GWT

Is there a way to disable the Back button in a browser (basically clearing the History token stack) in GWT? Once I browse to a certain page in my application I want to make sure that the user can't use the back button to go back, but only be able to use links on the page to navigate the site.
You cannot disable a button just intercept it and change its return to something the browser does not understand.
This removes the history:
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
event.setMessage("My program");
}
});
To understand it see: http://groups.google.com/group/google-web-toolkit/browse_thread/thread/8b2a7ddad5a47af8/154ec7934eb6be42?lnk=gst&q=disable+back+button#154ec7934eb6be42
However, I would recommend not doing this because your it goes against good UI practices. Instead you should figure out a way that the back button does not cause a problem with your code.
Call the method below in the onModuleLoad().
private void setupHistory() {
final String initToken = History.getToken();
if (initToken.length() == 0) {
History.newItem("main");
}
// Add history listener
HandlerRegistration historyHandlerRegistration = History.addValueChangeHandler(new ValueChangeHandler() {
#Override
public void onValueChange(ValueChangeEvent event) {
String token = event.getValue();
if (initToken.equals(token)) {
History.newItem(initToken);
}
}
});
// Now that we've setup our listener, fire the initial history state.
History.fireCurrentHistoryState();
Window.addWindowClosingHandler(new ClosingHandler() {
boolean reloading = false;
#Override
public void onWindowClosing(ClosingEvent event) {
if (!reloading) {
String userAgent = Window.Navigator.getUserAgent();
if (userAgent.contains("MSIE")) {
if (!Window.confirm("Do you really want to exit?")) {
reloading = true;
Window.Location.reload(); // For IE
}
}
else {
event.setMessage("My App"); // For other browser
}
}
}
});
}
I found a way to make GWT ignore the back-button: Just add historyitem x if no historyitem was set and do nothing on x.
set a historyitem on startup
History.newItem("x")
in the ValueChangeHandler of History add the following:
String historyToken = event.getValue();
if (!historyToken.equals("x"))
History.newItem("x");
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
event.setMessage("My program");
}
});
That is not a fool proof solution. In fire fox I can press the back button and the onWindowClosing method is never invoked. The reason is that I have used History.newItem() and since history exists the back button or backspace buttons simply navigate through the browser history.
So....fix that :)
Put this in your index.html file:
window.open('html page(For example trial.html)', 'Name of the desired site', width='whatever you want',height='whatever you want', centerscreen=yes, menubar=no,toolbar=no,location=no,
personalbar=no, directories=no,status=no, resizable=yes, dependent=no, titlebar=no,dialog=no');

Categories

Resources