11
votes

I was wondering if anyone could explain to me how I could properly bind a group of radio buttons to a boolean variable in the model using JFace data binding.

Let me explain the situation first: I've created a class that represents a group of SWT buttons (with the style set to 'SWT.RADIO') that consists of three elements: A label with the question and two buttons, one for the "yes" answer and one for a "no". I would like to create a binding to a boolean variable in the model in such a way that when a user selects the "yes" radio button the boolean is set to true, and when he/she selects the "no" button the boolean is set to false.

Here's the code of my class:

private class YesOrNoRadioButtonGroup {

private static final String YES = "yes";
private static final String NO = "no";
private Button m_yesButton;
private Button m_noButton;

public YesOrNoRadioButtonGroup(final Composite p_parent,
                               final String p_questionText,
                               final IObservableValue p_modelProperty
                               final DataBindingContext p_dbContext) 
{

  Composite radioButtonGroupContainer = new Composite(p_parent, SWT.NONE);
  radioButtonGroupContainer.setLayout(new GridLayout());
  Label question = new Label(radioButtonGroupContainer, SWT.NONE);
  question.setText(p_questionText);


  m_yesButton = new Button(radioButtonGroupContainer, SWT.RADIO);
  m_yesButton.setText(YES);

  m_noButton = new Button(radioButtonGroupContainer, SWT.RADIO);
  m_noButton.setText(NO);
  m_noButton.setSelection(true);

  Listener yesOrNoRadioGroupListener = new Listener() {

    public void handleEvent(Event p_event) {

      Button button = (Button) p_event.widget;

      if (m_yesButton.equals(button)) {
        m_yesButton.setSelection(true);
        m_noButton.setSelection(false);
      }
      else {
        m_yesButton.setSelection(false);
        m_noButton.setSelection(true);
      }
    }
  };

  m_yesButton.addListener(SWT.Selection, yesOrNoRadioGroupListener);
  m_noButton.addListener(SWT.Selection, yesOrNoRadioGroupListener);

  p_dbContext.bindValue(SWTObservables.observeSelection(this.getYesButton()),
      p_modelProperty, null, null);      
}

public Button getYesButton() {
  return m_yesButton;
}

public Button getNoButton() {
  return m_noButton;
}    


}

Now, as you can see, I'm binding my "yes" button to the boolean. Specifically, the value will be bound on the SWT.selection event. This is, it seems, the only valid event for the binding of a radio button. However, because of this, once the "no" button is selected, the value of the boolean remains unchanged (since no SWT.selection event on the "yes" button was fired).
What can I do to make this work the way it's supposed to, i.e. to be able to change the value of the boolean in the model based on which of the buttons the user selects? Am I missing something obvious here? Thanks!

6

6 Answers

7
votes

It seems similar to binding a POJO to a property.

That means you should have one object with your two buttons implementing an IObservable, and then bind it to your property.
As you mention in the comments, you should extend AbstractObservable.

You have an example of such an extension here with this class Test about an observable list (not necessary what you need but it can give you ideas about the use of Observable when it comes to detect the change upon notification)

7
votes

I think I found the most appropiate implementation for this. You need to use the org.eclipse.core.databinding.observable.value.SelectObservableValue. here is the code

class YesNoModel{
   public static enum RESPONSE {YES,NO};
   private RESPONSE value;
   public RESPONSE getValue(){return value;}
   public void setValue(RESPONSE value){this.value = value;}
}
class YouGraphicalClass {
   YesNoModel yesNomodel  = new YesNoModel();
   void iniDataBinding(){
        IObservableValue yesBtnSelection  = SWTObservables.observeSelection(this.getYesButton());
        IObservableValue noBtnSelection  = SWTObservables.observeSelection(this.getNoButton());
        SelectObservableValue featureRepoPolicyObservable = new SelectObservableValue(YesNoModel.RESPONSE.class);
        featureRepoPolicyObservable.addOption(RESPONSE.YES, yesBtnSelection);
        featureRepoPolicyObservable.addOption(RESPONSE.NO, noBtnSelection);
        p_dbContext.bindValue(featureRepoPolicyObservable,
                PojoObservables.observeValue(yesNomodel, "value"));
    }

This works of course for al kind of enums or other kind of selectable values. You could of course use you String YES and NO, but I prefer enums

2
votes

If use you the Nebula RadioGroup control you can use RadioGroupViewer and bind the viewer selection like any other viewer e.g. ComboViewer

2
votes

The radio buttons within the same composite would act as a group, therefore, only one button will have a true value and all others should have a false value. Along with this fact, the observeSelection on Yes Button should be sufficient enough to reflect the selected value of yes or no, at the model property side.

Or in other words, the modified constructor would look like this.

public YesOrNoRadioButtonGroup(final Composite p_parent,
            final String p_questionText,
            final IObservableValue p_modelProperty,
            final DataBindingContext p_dbContext) 
{
    Composite radioButtonGroupContainer = new Composite(p_parent, SWT.NONE);
    radioButtonGroupContainer.setLayout(new GridLayout());
    Label question = new Label(radioButtonGroupContainer, SWT.NONE);
    question.setText(p_questionText);

    m_yesButton = new Button(radioButtonGroupContainer, SWT.RADIO);
    m_yesButton.setText(YES);
    m_noButton = new Button(radioButtonGroupContainer, SWT.RADIO);
    m_noButton.setText(NO);
    m_noButton.setSelection(true);
    p_dbContext.bindValue(SWTObservables.observeSelection(this.getYesButton()),
                p_modelProperty, null, null);   
}

I tried this and found working well. Just check out.

0
votes

This is what I ended up with when mapping radio buttons to enum (I will proceed and make it reusable in our project) - using ISWTObservableValue saves the effort of adding the listeners:

    final ISWTObservableValue upload = SWTObservables.observeSelection(btnUpload);
    final ISWTObservableValue download = SWTObservables.observeSelection(btnDownload);
    final ISWTObservableValue noTransfer = SWTObservables.observeSelection(btnNoTransfer);
    final IObservableValue btns = new ComputedValue(ExecutableTransferModes.class) {

        @Override
        protected void doSetValue(final Object value) {
            boolean u = false, d = false, n = false;
            switch ((ExecutableTransferModes) value) {
            case Upload:
                u = true;
                break;
            case Download:
                d = true;
                break;
            case Notransfer:
                n = true;
                break;
            }
            upload.setValue(u);
            download.setValue(d);
            noTransfer.setValue(n);
        }

        @Override
        protected Object calculate() {
            if (Boolean.TRUE.equals(upload.getValue())) {
                return ExecutableTransferModes.Upload;
            } else if (Boolean.TRUE.equals(download.getValue())) {
                return ExecutableTransferModes.Download;
            } else if (Boolean.TRUE.equals(noTransfer.getValue())) {
                return ExecutableTransferModes.Notransfer;
            } else {
                return null;
            }
        }
    };
    bindingContext.bindValue(btns, uploadProperty);
0
votes

This should work with little to no effort, and we all know that's the best kind of answer right?

public static final void createAndBind(
    final DataBindingContext dbc, 
    final Composite parent,
    final Object bean, 
    final List<Object> options, 
    final String fieldName, 
    final Class<?> fieldType) {
    //
    List<Button> radios = new ArrayList<>();
    Button b;
    for (Object option : options) {
        b = new Button(parent, SWT.RADIO);
        b.setText(option.toString());
        b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        radios.add(b);
    }
    //
    List<IObservableValue> iovs = new ArrayList<>();
    IObservableValue iov;
    for (Button radio : radios) {
        iov = SWTObservables.observeSelection(radio);
        iovs.add(iov);
    }
    SelectObservableValue observable = new SelectObservableValue(fieldType);
    //
    for (int i = 0; i < options.size(); i++) {
        observable.addOption(options.get(i), iovs.get(i));
    }
    //
    dbc.bindValue(observable, PojoObservables.observeValue(bean, fieldName));
}