Need a better way of creating a list of text field objects

edited January 2017 in Library Questions

Hi there,

Have constructed a bit of code that creates say 5 text fields along with corresponding submit buttons.

Have managed this with For Loops. Is there a more elegant way to do this?

I feel my code can be improved as it would be very cumbersome to keep copy-pasting and changing the relative numbers especially for the submit() function. The overall code would take up too much space.

Can the submit function reside within a for loop as well?

Would love to hear some ideas so that I can take it forward. Thanks!

Here is the code I'm using:

import controlP5.*;

ControlP5 cp5;

// Should we do an array for this initialization?
// I don't want to type out say 30 textValues. What is the more elegant way to represent this?
// Arrays.fill()??

String textValue_1 = "";
String textValue_2 = "";
String textValue_3 = "";
String textValue_4 = "";
String textValue_5 = "";

void setup() {
  size(800, 1000);
  cp5 = new ControlP5(this);

  for (int i = 1; i < 6; ++i) {
    cp5.addTextfield("textValue" + "_" + i)
      .setPosition(20, 80*i)
        .setSize(200, 40)
          .setFont(createFont("arial", 20))
            .setCaptionLabel("Enter Text for field " + i)
              .setAutoClear(false)
                ;

    cp5.addButton("submit"+ "_" + i)
      .setPosition(240, 80*i)
        .setSize(80, 40)
          .setCaptionLabel("submit")
            .getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER)
              ;
  }
} 

void draw() {
  background(0);
}

// The function for submit... can this be done in a for loop?
// I may want a large number of text fields
// and it can get tedious typing it all out every time I change the number


public void submit_1() {
  cp5.get(Textfield.class, "textValue_1").submit();
}

public void submit_2() {
  cp5.get(Textfield.class, "textValue_2").submit();
}

public void submit_3() {
  cp5.get(Textfield.class, "textValue_3").submit();
}

public void submit_4() {
  cp5.get(Textfield.class, "textValue_4").submit();
}

public void submit_5() {
  cp5.get(Textfield.class, "textValue_5").submit();
}


void controlEvent(ControlEvent theEvent) {
  if (theEvent.isAssignableFrom(Textfield.class)) {
    println("controlEvent: accessing a string from controller '"
      +theEvent.getName()+"': "
      +theEvent.getStringValue()
      );
  }
}

Answers

  • Hey, a for-loop looks like a good way to simplify multiple similiar tasks. Another one is using arrays. But in this case it could be enough to work with IDs.

    I made some modifications to your code, maybe this helps:

    import controlP5.*;
    
    ControlP5 cp5;
    
    // array to store texts
    String[] textValues = {"...", "text", "write here", "", "default"};
    
    
    void setup() {
      size(800, 1000);
      cp5 = new ControlP5(this);
    
      for (int i = 0; i < 5; ++i) {
        cp5.addTextfield("textField" + "_" + i)
          .setPosition(20, 80+80*i)
          .setSize(200, 40)
          .setFont(createFont("arial", 20))
          .setCaptionLabel("Enter Text for field " + i)
          .setAutoClear(false)
          .setText(textValues[i])
          ;
    
        cp5.addButton("submit"+ "_" + i)
          .setId(i)
          .setPosition(240, 80+80*i)
          .setSize(80, 40)
          .setCaptionLabel("submit")
          .getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER)
          ;
      }
    } 
    
    void draw() {
      background(0);
    }
    
    
    void controlEvent(ControlEvent theEvent) {
    
      // check if event came from a button
      if (theEvent.isAssignableFrom(Button.class)) {
    
        // get index of button
        int index = theEvent.getId();
    
        // get textfield that is associated to this id
        Textfield tf = cp5.get(Textfield.class, "textField" + "_" + index);
    
        // now we can do anything we want with the text from this textfield
        println("text from field #"+index+" is: " + tf.getText());
      }
    }
    
  • edited January 2017

    Thanks Benja... this really helps in understanding the use of Arrays as well as the concept of ids. But i am a little lost when it comes to buttons performing different functions?

    Submit and Clear buttons:

    Was going through and decided to add another set of buttons that would perform the 'clear' function. However, these buttons would have the same ids and don't perform the right function of clearing the text in the text field.

    I tried using 'j' instead of 'i' in an additional for loop only for the clear buttons but obviously the ids all start from 0 again and they overlap. So that fails.

    The current modified version shown below does not perform the 'clear' function. How can I set another range of ids for the 'clear' buttons? Thanks for all the help!

    import controlP5.*;
    
    ControlP5 cp5;
    
    // array to store texts
    String[] textValues = {
      "...", "text", "write here", "", "default"
    };
    
    
    void setup() {
      size(800, 1000);
      cp5 = new ControlP5(this);
    
      for (int i = 0; i < 5; ++i) {
        cp5.addTextfield("textField" + "_" + i)
          .setPosition(20, 80+80*i)
            .setSize(200, 40)
              .setFont(createFont("arial", 20))
                .setCaptionLabel("Enter Text for field " + i)
                  .setAutoClear(false)
                    .setText(textValues[3])
                      ;
    
        cp5.addButton("submit"+ "_" + i)
          .setId(i)
            .setPosition(240, 80+80*i)
              .setSize(80, 40)
                .setCaptionLabel("submit")
                  .getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER)
                    ;      
    
    
    
        // ADDING CLEAR BUTTON
        // This has the same set of id numbers. Should we create a separate for loop for this?
    
        cp5.addButton("clear"+ "_" + i)
          .setId(i)
            .setPosition(340, 80+80*i)
              .setSize(80, 40)
                .setCaptionLabel("clear")
                  .getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER)
                    ;
      }
    } 
    
    void draw() {
      background(0);
    }
    
    
    void controlEvent(ControlEvent theEvent) {
    
      // check if event came from a button
      if (theEvent.isAssignableFrom(Button.class)) {
    
        // get index of button
        // EDIT: How will controlEvent know that there is another set of ids 
        // coming from the clear() function.
        // ids are also integers or ints so one can't do differentiators like 1_1, 1_2, 1_3 OR 2_1, 2_2, 2_3
        // in the setId() i.e. .setId(1_1) is incorrect
        int index = theEvent.getId();
    
    
        // get textfield that is associated to this id
        Textfield tf = cp5.get(Textfield.class, "textField" + "_" + index);
    
        // now we can do anything we want with the text from this textfield
        println("text from field #"+index+" is: " + tf.getText());
      }
    }
    

    :)

  • Answer ✓

    Well, if it gets more complex, IDs might not work in the way i used them for that example. There was only button associated to each textfield.

    We could of course use names for the controllers like "submit_1" etc. and extract type and index from that string. But i thnk i prefer using arrays to store the controllers and use thy IDs to define the type of button, makes more sense to me.

    Here is an example of waht i mean:

    import controlP5.*;
    
    // just any unique id to identify type of button
    int SUBMIT_BUTTON_ID = 0;
    int CLEAR_BUTTON_ID = 1;
    
    ControlP5 cp5;
    Textfield[] textfields;
    Button[] clearButtons;
    Button[] submitButtons;
    
    int numOfTextfields = 5;
    
    
    void setup() {
      size(800, 1000);
      cp5 = new ControlP5(this);
    
      // create array to store cp5-elements
      textfields = new Textfield[numOfTextfields];
      clearButtons = new Button[numOfTextfields];
      submitButtons = new Button[numOfTextfields];
    
    
    
      for (int i = 0; i < numOfTextfields; ++i) {
    
        // assign controllers to one of the arrays when creating
    
        textfields[i] = cp5.addTextfield("textField" + "_" + i)
          .setPosition(20, 80+80*i)
          .setSize(200, 40)
          ;
    
        submitButtons[i] = cp5.addButton("submit"+ "_" + i)
          .setId(SUBMIT_BUTTON_ID)
          .setPosition(240, 80+80*i)
          .setSize(80, 40)
          .setCaptionLabel("submit")
          ;      
        submitButtons[i].getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
    
        clearButtons[i] = cp5.addButton("clear"+ "_" + i)
          .setId(CLEAR_BUTTON_ID)
          .setPosition(340, 80+80*i)
          .setSize(80, 40)
          .setCaptionLabel("clear")
          ;
        clearButtons[i].getCaptionLabel().align(ControlP5.CENTER, ControlP5.CENTER);
      }
    } 
    
    void draw() {
      background(0);
    }
    
    
    void controlEvent(ControlEvent theEvent) {
    
      // check if event came from a button
      if (theEvent.isAssignableFrom(Button.class)) {
    
        int buttonType = theEvent.getId();
    
        // if event is from a submit button
        if (buttonType == SUBMIT_BUTTON_ID) {
    
          // iterate over all submit-buttons to check which button the event came from
          for (int i =0; i< submitButtons.length; i++) {
    
            if (theEvent.getController().equals(submitButtons[i])) {
              // now we know the event came from the i-th submit button
              println("event came from submit button #"+i);
              // so we can now easily use the text from the i-th textfield
              println("submit text: "+textfields[i].getText());
            }
          }
        }
    
    
        // and we do it simiar for submit-button events
        if (buttonType == CLEAR_BUTTON_ID) {
          for (int i =0; i< clearButtons.length; i++) {
            if (theEvent.getController().equals(clearButtons[i])) {
              println("clearing textfield #"+i);
              textfields[i].setText("");
            }
          }
        }
      }
    }
    

    As a next step i would recommend to create a class for such a group of controllers, makes things much more organized. A good introduction to this topic is here: https://forum.processing.org/two/discussion/8081/from-several-arrays-to-classes

  • Thanks Benja, you have explained this very well and am able to understand completely. Thanks so much for all your help. I'm still learning and hopefully will be able to work out the classes to make this code better. But for now this is awesome! :-) :-) :-) Cheers!

Sign In or Register to comment.