Remove objects with many CP5 controllers

edited May 2017 in Library Questions

Hello, I'm rather new to Processing, so please bear with me. I am writing code to allow me to control multiple servos with two CP5 sliders. I hope to make it variable, allowing for a pair for each servo attached. I have made a class for the slider pairs (SvoPkg), and have no issues using a bang to call them up. However, I'm stuck on how to make them disappear. I'm using an ArrayList to call the object, but remove() will only clear the List, not the objects on screen. Similarly, since the sliders are nested in an object, I can't seem to remove them piecemeal using .getController().remove() either (I get a Static/non-static error). I've tried using the draw() function to add the object to better update the screen when the List is cleared, but that won't work because the sliders aren't usable anymore -the draw loop make them essentially a picture and immobile. I'd like to basically have a remove() function for the object (like CP5 has for its individual controllers), but don't quite know how to implement one.

Here is a dumbed-down version of the code; for clarity's sake I'm just using one Package and have altered the position data. Right now, I'm trying to just use one bang to make the object, and the other to remove it.

    import controlP5.*;
    ControlP5 gui;

    ArrayList<SvoPkg> layout;
    int PkgTot = 1;

    void setup(){
      size (300, 150);
    gui = new ControlP5(this);
      layout = new ArrayList<SvoPkg>();
      fill(230,170,90);

    gui.addBang ("Make")
      .setPosition(200,95)
      .setSize(40,30)
      ;
    gui.addBang ("Kill")
      .setPosition(250,95)
      .setSize(40,30)
      ;
    }
    void draw(){
     background(190,130,30);
        }

    void Make(){
      for(int i=0; i<PkgTot;i++){
          layout.add(new SvoPkg(this, 20, 30));
         }     
     }
     void kill(){ //I've left this blank for now, but is where I'd like to remove the object
     }

     class SvoPkg {
      PApplet app;
      ControlP5 Objgui;

    SvoPkg(PApplet papp, float Xpos, float Ypos){
     app = papp;
     Objgui = new ControlP5(papp);

    Objgui.addSlider("Angle")
       .setPosition(Xpos+15, Ypos+ 15)
       .setSize(120, 10)
       .setRange(600,2400)
       ;
    Objgui.addSlider("Speed")
      .setPosition(Xpos+15, Ypos + 30)
      .setSize(120, 10)
      .setRange(50,1000)
      ;
    }
    }

Thanks for your input

Answers

  • Why do you need an array of SvoPkg? Do you need it?

    Here is my solution below. Let me know if it doesn't work in your case. My approach is, instead of destroying/deleting the objects, to recycle them.

    NOTE: Classes start with upper case. Variables, method names, object instances start with lower case and either in camelName or serpent_name notation.
    Also notice you don't really need the class SvoPkg at the end. You can define a second controlP5 in the same scope as gui based on my solution. However, my idea might not be suitable to your design.

    Lastly, my code is not tested, so watch for typos or errors....

    Kf

    import controlP5.*;
    ControlP5 gui;
    
    SvoPkg layout;
    
    void setup(){
      size (300, 150);
      gui = new ControlP5(this);
      make();
    show();
      fill(230,170,90);
    
    gui.addBang ("Make")
      .setPosition(200,95)
      .setSize(40,30)
      ;
    gui.addBang ("Kill")
      .setPosition(250,95)
      .setSize(40,30)
      ;
    }
    void draw(){
     background(190,130,30);
        }
    
    void make(){  
          layout=new SvoPkg(this, 20, 30);      
     }
    
    void show(){
      layout.Objgui.show();
    }
    
     void kill(){ //I've left this blank for now, but is where I'd like to remove the object
        layout.Objgui.hide();
     }
    
     class SvoPkg {
      PApplet app;
      ControlP5 Objgui;
    
    SvoPkg(PApplet papp, float Xpos, float Ypos){
     app = papp;
     Objgui = new ControlP5(papp);
    
    Objgui.addSlider("Angle")
       .setPosition(Xpos+15, Ypos+ 15)
       .setSize(120, 10)
       .setRange(600,2400)
       ;
    Objgui.addSlider("Speed")
      .setPosition(Xpos+15, Ypos + 30)
      .setSize(120, 10)
      .setRange(50,1000)
      ;
    }
    }
    
  • Thanks for the reply. Your code works well, I messed with the setup declarations to not have the package appear at the start, but it was what I was looking for. Cheers!

    I am using an ArrayList because I eventually intend to have 12+ of these controllers, and to have them able to toggle on/off. I figured this would be a better way to manage that many. As it stands, I'm working through the finer points of making sure the List is updated appropriately. I'm thinking I may have to use a full array[] instead, but I'm giving it a try this way.

    I'm working on integrating these suggestions into my larger code and will post soon to illustrate. Cheers

  • Here's an example code using the ArrayList for flexibility.

            import controlP5.*;
                ControlP5 gui;
    
            ArrayList<SvoPkg> layout;
            int pkgTot = 3;
    
            void setup() {
              size (550, 200);
              gui = new ControlP5(this);
              layout = new ArrayList<SvoPkg>();
            gui.addBang ("Set")
                .setPosition(width*.8, height*.7)
                .setSize(40, 30)
                ;
            gui.addBang ("Kill")
                .setPosition(width*.9, height*.7)
                .setSize(40, 30)
                ;
            for (int j=0; j<pkgTot; j++) {
                String namJ = "Tog"+(j+1);
                makeTog(namJ, j, .8);
              }
            }
            void draw() {
              background(190, 130, 30);
            }
            Toggle makeTog(String togNam, int togNum, float vertPos) {
              return gui.addToggle(togNam)
                .setValue(1)
                .setPosition((width*.05+(60*togNum)), height*(vertPos))
                .setSize(20, 20)
                ;
            }
            void Set() {
              for (int i=0; i<pkgTot; i++) {
                String namI = "Tog"+(i+1);
                float state = gui.get(Toggle.class, namI).getValue();
                if (state == 1) {        
                  layout.add(new SvoPkg(this, 20+(175*i), 30));
                }
              }
            }
            void Kill() {
               for (int i=0;i<layout.size();i++){
                   layout.get(i).gui.hide();
              } 
             layout.clear();
            }
    class SvoPkg {
      PApplet app;
      ControlP5 gui;
    
    SvoPkg(PApplet papp, float tempX, float tempY){
     app = papp;
     gui = new ControlP5(papp);
    
    gui.addSlider("Angle")
       .setPosition(tempX+15, tempY+ 15)
       .setSize(100, 10)
       .setRange(600,2400)
    .plugTo(this,"setValue")
       ;
    gui.addSlider("Speed")
      .setPosition(tempX+15, tempY + 30)
      .setSize(100, 10)
      .setRange(50,1000)
      ;
     }
    }
    

    I plan on a toggle (Tog) for each servo, and this method seems to work pretty well for me so far. My next step is to integrate the two bangs into one, so I when the "set" bang is hit, any checked toggles will produce a corresponding slider package, and if not, the sliders will be removed.

  • Great! Thanks for sharing.

    Kf

  • edited May 2017

    Update: I decided to try expanding this model to a controlFrame where the toggles are in a separate window, and running the code would have the sliders appear in the main window. I'm hitting a roadblock in my ignorance about how to call and address between two separate frames: Main sketch

    import controlP5.*;
        ControlP5 cp5;
        ControlFrame togWin;
    
        ArrayList<SvoPkg> layout = new ArrayList<SvoPkg>();
        int pkgTot = 3;
    
        void settings (){
         size (600,200); 
        }
    
        void setup() {
          cp5= new ControlP5(this);
          togWin = new ControlFrame(this, 500,200, "SetServos");
    
        cp5.addBang ("Remove")
            .setPosition(width*.85, height*.7)
            .setSize(40, 30)
            ;
          }
        void draw() {
          background(190, 130, 30);
        }
        void Remove() {
          for (int i=0;i<layout.size();i++){
          //this is where I'm unsure about the proper address foramt to call
          //another frames' controllers or CP5 builds. 
            //       layout.get(i).cp5.hide();
          } 
         layout.clear();
        }
        class SvoPkg {
        PApplet app;
    
        SvoPkg(PApplet papp, int numb, float tempX, float tempY){
         app = papp;
    
        cp5.addSlider("Angle"+numb)
           .setPosition(tempX+15, tempY+ 15)
           .setSize(100, 10)
           .setRange(600,2400)
        .plugTo(this,"setValue")
           ;
        cp5.addSlider("Speed"+numb)
          .setPosition(tempX+15, tempY + 30)
          .setSize(100, 10)
          .setRange(50,1000)
          ;
         }
        }
    

    New Frame Tab "NewFrame

        class ControlFrame extends PApplet {
              int w, h;
              PApplet parent;
              ControlP5 winCP;
                int totNum = 3;
    
            public ControlFrame(PApplet _parent, int _w, int _h, String _name) {
                super();   
             parent = _parent;
                w = _w;
                h = _h;
             PApplet.runSketch(new String[]{this.getClass().getName()}, this);
              }
            public void settings() {
                size(w,h);
              }
            public void setup() {
               winCP = new ControlP5(this);
    
            winCP.addBang("Set")
                .setPosition(width*.75, height*.8)
                .setSize(30,20)
                .getCaptionLabel()
                .align(ControlP5.CENTER,ControlP5.BOTTOM_OUTSIDE)
                ;
            winCP.addBang("Kill")
                .setPosition(width*.85, height*.8)
                .setSize(30,20)
                .getCaptionLabel()
                    .align(ControlP5.CENTER,ControlP5.BOTTOM_OUTSIDE)
                ;
            for (int j=0; j<totNum; j++) {
                String namJ = "Tog"+(j+1);
                makeTog(namJ, j, .8);
               }
            }
            Toggle makeTog(String togNam, int togNum, float vertPos) {
              return winCP.addToggle(togNam)
                .setValue(0)
                .setPosition((width*.05+(60*togNum)), height*(vertPos))
                .setSize(20, 20)
                ;
            }
            void draw(){
              background(0);
            }
            void Set() {
              for (int i=0; i<totNum; i++) {
                String namI = "Tog"+(i+1);
                float state = winCP.get(Toggle.class, namI).getValue();
                if (state == 1) {        
                  layout.add(new SvoPkg(this, (i+1),20+(175*i), 30));
                }
                else{
                 print("toggle ");print(i);println("not flipped"); 
                }
              }
            }
          }
    

    I'm obviously new to the use of Frames (and the examples still don't work for me (processing 3.3, CP5 2.2.5) so most of my build is from the generics. I'm running into trouble with the removal functions not working and think as a result I'm getting redundant controllers ("Controller with the name...already exists). I can get the sliders to populate, but not delete with another button. I've not tried to tackle the single button appear/remove using toggles yet.

  • Sorry about the formatting. I fixed it. I think I can figure most of this out once I understand the proper means of using one controller in one window to reference/control/.hide() another. Thanks

  • Notice your class SvoPkg in the main sketch is accessing cp5 which is global. It is not a member of your class. So what you are trying to do in line 28: layout.get(i).cp5.hide(); is not correct. You have two options. Either interact with the global object directly: cp5.hide() or you make cp5 as a member object of your SvoPkg class:

    class SvoPkg {
    
      ControlP5 cp5;
    
      //Contructor
      SvoPkg(){ ...}
    
    }
    

    I am not sure what is the relationship between your main and NewFrame sketch. For starters, I think you should be calling runSketch from main and no from NewFrame's constructor. Check these examples:

    https://forum.processing.org/two/discussion/17520/pop-up-window#latest
    https://forum.processing.org/two/discussion/comment/72574/#Comment_72574

    Kf

Sign In or Register to comment.