How Smart-gwt SC.askforValue() cancel can be handled? - java

My Question:
In the code below I try to ask user a value. SC.askforValue() is called with all possible variables, a Dialog is given as parameter to adjust the dialog.
My problem is what happens, when user presses cancel? On my current smartGwt version (2.1), is it possible to see the cancel alone? Now empty value and cancel get both handled in the same way.
My Code:
Dialog dialog = new Dialog();
dialog.setWidth(200);
SC.askforValue("myTitle", "myQuestion", "defaultValue", new ValueCallback() {
#Override
public void execute(String value) {
if (value != null) {
// do sth.
} else {
/* cancel pressed / empty value. */
}
}
}, dialog);

As per the documentation,
if you want to differantiate blank input and cancel event, you can check the value, you receive in the callback. When user has entered nothing and clicks OK, blank string will be there as value. And when user clicks Cancel, the value will be null.

Related

How to know if input dialog is opened in Java GUI

I am working on a project that tests Java programs using JUnit5. And in this case, I want to verify that when a button is clicked, it will really open an input dialog.
private void updateTextButtonActionPerformed(java.awt.event.ActionEvent evt) {
String newString = JOptionPane.showInputDialog("Enter a string.");
}
The only way I can think of that the input dialog function has really been implemented is when I can simulate on my test that during button click, an input dialog has been opened.
So the test will be successful if an input dialog has been opened on button click, while failure if not.
UPDATE:
The Mock function of JOptionPane:
#Test
public void shouldShowInputDialogOnUpdateTextButtonClick() {
try (MockedStatic<JOptionPane> jOptionPane = mockStatic(JOptionPane.class)) {
// TODO: Check whether 'showInputDialog' has been called. But how?
}
updateTextButton = (JButton) TestUtils.getChildNamed(activity1, "updateTextButton");
updateTextButton.doClick(); // Performs updateTextButtonActionPerformed() function
}

How I can control flow of execution in GWT?

If you have ever used Window.alert("msg"); API in GWT to show popup, I am not sure but the call to this API pauses the code execution until a user action is taken (cliking the ok button), Simillar to that i have created a custom popup, when it is shown i don't want the code to execute further till any user input in received on the popup, How can i pause the code execution further?
Assume :-
//Some Code
MY Popup (Here i want to wait till a user action is received.)
//Some code
I read somewhere to use Synchronized key word but that didn't work either,Do you have answer to this. How GWT compiler sees "Synchronized" keyword does it ignores the keyword?
Create something like a ConfirmCallBack that you fire when the "OK" button (or whatever) is clicked in the popuppanel.
//method in your own popup class
public static void confirm(String message, ConfirmCallBack confirmCallBack)
{
Button confirmButton = new Button(confirmButtonText, event ->
{
confirmCallBack.callback(true);
//hide popup
});
}
Than also have the ConfirmCallBack interface like
public interface ConfirmCallBack
{
void callback(boolean result);
}
Then call your own popup like
MyPopup.confirm("Hello world", result ->
{
if (result)
{
//my code to be executed after clicking the ok button
}
}

Set default value of JSwing checkbox?

I currently have an actionListener set up to detect whether or not the checkBox I have created is checked, and depending on this; set the value of taskType to either 'oneOff' (unchecked) or 'Routine (checked). The problem is that when the user submits the form by clicking the button, the received value is 'null' if the box is left unchecked, the only way to make the received value 'oneOff' is by checking the box and unchecking it again. How can I make the default unchecked value of the checkbox 'oneOff' - and is this even possible?
checkBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
if(freqComboBox.getSelectedIndex() == -1 && checkBox.isSelected())
{
freqLabel.setEnabled(true);
freqComboBox.setEnabled(true);
createTask.setEnabled(false);
}
else if(checkBox.isSelected())
{
freqLabel.setEnabled(true);
freqComboBox.setEnabled(true);
taskType = "Routine";
}
else
{
freqLabel.setEnabled(false);
freqComboBox.setEnabled(false);
freqComboBox.setSelectedIndex(-1);
taskType = "oneOff";
}
}
});

Manually typing in text in JavaFX Spinner is not updating the value (unless user presses ENTER)

It seems that the Spinner control does not update a manually typed-in value until the user explicitly presses enter. So, they could type in a value (not press enter) exit the control, and submit the form, and the value displayed in the spinner is NOT the value of the Spinner, it is the old value.
My idea was to add a listener to the lost focus event, but I can't see a way to gain access to the typed-in value?
spinner.focusedProperty().addListener((observable, oldValue, newValue) ->
{
//if focus lost
if(!newValue)
{
//somehow get the text the user typed in?
}
});
This is odd behavior, it seems to go against the convention of a GUI spinner control.
Unfortunately, Spinner doesn't behave as expected: in most OS, it should commit the edited value on focus lost. Even more unfortunate, it doesn't provide any configuration option to easily make it behave as expected.
So we have to manually commit the value in a listener to the focusedProperty. On the bright side, Spinner already has code doing so - it's private, though, we have to c&p it
/**
* c&p from Spinner
*/
private <T> void commitEditorText(Spinner<T> spinner) {
if (!spinner.isEditable()) return;
String text = spinner.getEditor().getText();
SpinnerValueFactory<T> valueFactory = spinner.getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
// useage in client code
spinner.focusedProperty().addListener((s, ov, nv) -> {
if (nv) return;
//intuitive method on textField, has no effect, though
//spinner.getEditor().commitValue();
commitEditorText(spinner);
});
Note that there's a method
textField.commitValue()
which I would have expected to ... well ... commit the value, which has no effect. It's (final!) implemented to update the value of the textFormatter if available. Doesn't work in the Spinner, even if you use a textFormatter for validation. Might be some internal listener missing or the spinner not yet updated to the relatively new api - didn't dig, though.
Update
While playing around a bit more with TextFormatter I noticed that a formatter guarantees to commit on focusLost:
The value is updated when the control loses its focus or it is commited (TextField only)
Which indeed works as documented such that we could add a listener to the formatter's valueProperty to get notified whenever the value is committed:
TextField field = new TextField();
TextFormatter fieldFormatter = new TextFormatter(
TextFormatter.IDENTITY_STRING_CONVERTER, "initial");
field.setTextFormatter(fieldFormatter);
fieldFormatter.valueProperty().addListener((s, ov, nv) -> {
// do stuff that needs to be done on commit
} );
Triggers for a commit:
user hits ENTER
control looses focus
field.setText is called programmatically (this is undocumented behaviour!)
Coming back to the spinner: we can use this commit-on-focusLost behaviour of a formatter's value to force a commit on the spinnerFactory's value. Something like
// normal setup of spinner
SpinnerValueFactory factory = new IntegerSpinnerValueFactory(0, 10000, 0);
spinner.setValueFactory(factory);
spinner.setEditable(true);
// hook in a formatter with the same properties as the factory
TextFormatter formatter = new TextFormatter(factory.getConverter(), factory.getValue());
spinner.getEditor().setTextFormatter(formatter);
// bidi-bind the values
factory.valueProperty().bindBidirectional(formatter.valueProperty());
Note that editing (either typing or programmatically replacing/appending/pasting text) does not trigger a commit - so this cannot be used if commit-on-text-change is needed.
#kleopatra headed to a right direction, but the copy-paste solution feels awkward and the TextFormatter-based one did not work for me at all. So here's a shorter one, which forces Spinner to call it's private commitEditorText() as desired:
spinner.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
spinner.increment(0); // won't change value, but will commit editor
}
});
This is standard behavior for the control according to the documentation:
The editable property is used to specify whether user input is able to
be typed into the Spinner editor. If editable is true, user input will
be received once the user types and presses the Enter key. At this
point the input is passed to the SpinnerValueFactory converter
StringConverter.fromString(String) method. The returned value from
this call (of type T) is then sent to the
SpinnerValueFactory.setValue(Object) method. If the value is valid, it
will remain as the value. If it is invalid, the value factory will
need to react accordingly and back out this change.
Perhaps you could use a keyboard event to listen to and call the edit commit on the control as you go.
Here is an improved variant of Sergio's solution.
The initialize method will attach Sergio's code to all Spinners in the controller.
public void initialize(URL location, ResourceBundle resources) {
for (Field field : getClass().getDeclaredFields()) {
try {
Object obj = field.get(this);
if (obj != null && obj instanceof Spinner)
((Spinner) obj).focusedProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue) {
((Spinner) obj).increment(0);
}
});
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Using a listener should work. You can get access to the typed in value through the spinner's editor:
spinner.getEditor().getText();
I use an alternate approach - update it live while typing. This is my current implementation:
getEditor().textProperty().addListener { _, _, nv ->
// let the user clear the field without complaining
if(nv.isNotEmpty()) {
Double newValue = getValue()
try {
newValue = getValueFactory().getConverter().fromString(nv)
} catch (Exception e) { /* user typed an illegal character */ }
getValueFactory().setValue(newValue)
}
I used this approach
public class SpinnerFocusListener<T> implements ChangeListener<Boolean> {
private Spinner<T> spinner;
public SpinnerFocusListener(Spinner<T> spinner) {
super();
this.spinner = spinner;
this.spinner.getEditor().focusedProperty().addListener(this);
}
#Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
StringConverter<T>converter=spinner.getValueFactory().getConverter();
TextField editor=spinner.getEditor();
String text=editor.getText();
try {
T value=converter.fromString(text);
spinner.getValueFactory().setValue(value);
}catch(Throwable ex) {
editor.setText(converter.toString(spinner.getValue()));
}
}
}

CheckboxField gives StackOverflow Error in Blackberry java application

I am creating 2-3 checkbox field in my screen and adding those in a vertical field manager. Idea here is to disable other check box on click of another checkbox. but it is giving me stackoverflow error. I am posting my code here...
final CheckboxField[] checkBoxField = new CheckboxField[2];
checkBoxField[0] = cashCardCheckboxField;
checkBoxField[1] = creditDebitCardCheckboxField;
checkBoxField[0].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[0].getChecked()){
checkBoxField[0].setChecked(false);
}else{
checkBoxField[0].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[0].setChecked(false);
}
}
});
checkBoxField[1].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[1].getChecked()){
checkBoxField[1].setChecked(false);
}else{
checkBoxField[1].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[1].setChecked(false);
}
}
});
Thanks and Regards.
Solution
Try using this code. It allows you to create any number of checkboxes. When one is checked, the listener will uncheck all the other ones.
public class CheckBoxScreen extends MainScreen {
private CheckboxField checkBoxField[];
public CheckBoxScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
checkBoxField = new CheckboxField[3];
checkBoxField[0] = new CheckboxField("one", true); // checked by default
checkBoxField[1] = new CheckboxField("two", false);
checkBoxField[2] = new CheckboxField("three", false);
FieldChangeListener listener = new CheckboxListener();
for (int i = 0; i < checkBoxField.length; i++) {
checkBoxField[i].setChangeListener(listener);
add(checkBoxField[i]);
}
}
private class CheckboxListener implements FieldChangeListener {
public void fieldChanged(Field field, int context) {
if (context != FieldChangeListener.PROGRAMMATIC) {
// user modified this field
CheckboxField checkbox = (CheckboxField)field;
if (checkbox.getChecked()) {
// uncheck the other checkboxes
for (int i = 0; i < checkBoxField.length; i++) {
if (checkBoxField[i] != checkbox && checkBoxField[i].getChecked()) {
checkBoxField[i].setChecked(false);
}
}
}
} else {
// nothing more to do here ... this time, fieldChanged() is being
// called as a result of calling setChecked() in the code.
}
}
}
}
Why Your Code Created a Stack Overflow
The fieldChanged() method gets called whenever a field has its properties modified. For a CheckboxField, that happens when the field is checked or unchecked. This can happen either because the user checks/unchecks the field, or because your code calls setChecked(boolean). This line:
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
is what allows the code inside fieldChanged() to determine if this call is occurring because the user changed the field, or because setChecked() was called by your code. Unfortunately, you have placed calls to setChecked() in all branches of the if statement, which causes setChecked() to be called both for user events, and when your code changes the fields.
In this code:
checkBoxField[0].setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
if(context != FieldChangeListener.PROGRAMMATIC){ //It means manually clicked by User
if(checkBoxField[0].getChecked()){
checkBoxField[0].setChecked(false);
}else{
checkBoxField[0].setChecked(true);
//Please wait Screen starts
// call here a user defined function to populate the drop down list
//Please wait Screen ends
}
}else{
checkBoxField[0].setChecked(false);
}
}
});
it is the last line (checkBoxField[0].setChecked(false);) that is causing problems. That else branch is reached after calling setChecked() in the "manually clicked" branch of the if statement. Once you call setChecked(false) again, you have modified the field programmatically. This will cause fieldChanged() to be called back again. And again. And again. This loop will never stop, until the program stack is full, and your app crashes.
So, if you see my code, you notice that I am not calling setChecked() in the programmatic branch of the if statement. Another problem in your code is that you don't have the correct logic to uncheck checkbox 1 when checkbox 0 is checked. But, that's only a functional bug. The recursive call to fieldChanged() is what caused the stack overflow.
Hope that helps.

Categories

Resources