Help with button objects


#1

Hi, I have a class to define some buttons and I have my main application displaying a few of these (grouped in 2 separate arrays). Everything works fine except I’d like the “currently” active button to display a red line at the bottom. I have managed to do something similar but it doesn’t work as expected and I’m not sure why. Can you please take a look at my code? Thanks!

Button class

class Button{
  
  private int btnWidth;
  private int btnHeight;
  private int xPos;
  private int yPos;
  private int val;
  private Boolean btnActive;
  
  Button(int btnWidth, int btnHeight){
    this.btnWidth = btnWidth;
    this.btnHeight = btnHeight;
    this.xPos = width/2;
    this.yPos = height/2;
    this.btnActive = false;
  }
  
  public void btnSetAppearance(int strokeWeight, int strokeCol, int fillCol){
    strokeWeight(strokeWeight);
    stroke(strokeCol);
    fill(fillCol);
  }
  
  public void btnSetAppearance(int fillCol){
    noStroke();
    fill(fillCol);
  }
  
  public void btnDisplay(int xPos, int yPos){
    this.xPos = xPos;
    this.yPos = yPos;
    rectMode(CENTER);
    rect(this.xPos, this.yPos, btnWidth, btnHeight);
    
    if(this.btnActive){
      stroke(255,0,0);
      strokeWeight(2);
      line((this.xPos - this.btnWidth/2)+1, (this.yPos + this.btnHeight/2), (this.xPos + this.btnWidth/2)-2, (this.yPos + this.btnHeight/2));
    }
  }
  
  public void btnDisplay(){
    rectMode(CENTER);
    rect(this.xPos, this.yPos, btnWidth, btnHeight);
  }
  
  public void btnText(int fontSize, color fillCol, String text, int xPos, int yPos){
    fill(fillCol);
    textFont(font, fontSize);
    text(text, xPos, yPos);
  }
  
  public void btnSetVal(int val){
    this.val = val;
  }
  
  public int btnGetVal(){
    return this.val;
  }
  
  public int btnGetWidth(){
    return this.btnWidth;
  }
  
  public int btnGetHeight(){
    return this.btnHeight;
  }
  
  public void btnSetActive(){
    this.btnActive = true;
  }
  
  public void btnSetInactive(){
    this.btnActive = false;
  }
  
  public Boolean btnClicked(){
    if(mouseX >= (this.xPos - this.btnWidth/2) && mouseX <= (this.xPos + this.btnWidth/2)
      && mouseY >= (this.yPos - this.btnHeight/2) && mouseY <= (this.yPos + this.btnHeight/2))
        return true;
        
    return false;
  }

}

//Main app

import netP5.*;
import oscP5.*;

OscP5 oscSender;
NetAddress oscDestination;

PFont font;
float freq = 0.0;
float toSend = 0.0; //freq to send OSC
float drawFixed = 0.0;
float fixedFreq = 0.0;
float maxFreq = 1000;
Button btnsIntensity[] = new Button[10];
Button btnsFreqRange[] = new Button[3];
Button btnMain;
Boolean btnActive = false;

void setup()
{
  size(800,600);
  background(0);
  font = createFont("Arial",16,true);
  textFont(font,24);
  oscSender = new OscP5(this,12000);
  oscDestination = new NetAddress("127.0.0.1",12000); 
  
  for(int i = 0; i< 10; i++)
    btnsIntensity[i] = new Button(50, 20);
  
  for(int i = 0; i< 3; i++)
    btnsFreqRange[i] = new Button(75, 30);
    
  btnsIntensity[0].btnSetActive();
  btnsFreqRange[1].btnSetActive();
    
}

void draw()
{  
  //main
  background(3);
  rectMode(CORNER);
  stroke(100);
  strokeWeight(2);
  line(mouseX, 0, mouseX, height);
  
  //selected freq
  stroke(255);
  line(drawFixed, 0, drawFixed, height);
  
   //selected freq container
   noStroke();
   fill(200);
   rect(0, 0, width, 50);
   
   //intensity btns container
   fill(255);
   rect(0,50,width,30);
   
  //white block bottom
  rect(0, height-50, width, height-50);
  
  //map freq
  freq = (int) map(mouseX, 0.0, width, 0.0, maxFreq);
  
  //maxFreq btns  
  for(int i=0; i<3; i++)
  {
    if(i==0)
      btnsFreqRange[i].btnSetAppearance(color(150,150,50));
    else if(i==1)
      btnsFreqRange[i].btnSetAppearance(color(150, 200, 50));
    else
      btnsFreqRange[i].btnSetAppearance(color(150, 250, 50));
      
    btnsFreqRange[i].btnDisplay((width/3-btnsFreqRange[i].btnGetWidth()) + ((i+1) * 100), height-25);
    btnsFreqRange[i].btnText(16, 0, Integer.toString(500*(i+1)), (width/3-btnsFreqRange[i].btnGetWidth()) + ((i+1) * 95), height-20);
    btnsFreqRange[i].btnSetVal(500*(i+1));
  }
  
  //intensity btns  
  for(int i=0; i<10; i++)
  {
    if(i==0)
      btnsIntensity[i].btnSetAppearance(color(250,150,50));
    else if(i==9)
      btnsIntensity[i].btnSetAppearance(color(50, 150, 150));
    else
      btnsIntensity[i].btnSetAppearance(color(250, 250, 50));
      
    btnsIntensity[i].btnDisplay(70*(i+1), 65);
    btnsIntensity[i].btnText(16, 0, Integer.toString(i), 70*(i+1)-5, 70);
    btnsIntensity[i].btnSetVal(i);
  }
  
  textFont(font, 24);
  //current frequency text
  fill(0);
  text("Hz: " + freq, 50, height-10);
  
  //current selected frequency text
  fill(255,0,0);
  text("Hz: " + (int)map(drawFixed,0,width,0,maxFreq), width/2-50, 35);

}

void mouseClicked()
{
 
 //select freq and send it
 if(mouseX >=0 && mouseX <= width && mouseY >= 80 && mouseY <= height-50)
 {
   sendOSCMsg(freq, "/freq");
   drawFixed = mouseX;
 }
 
 //check if any btn was clicked
 for(int i=0; i<3; i++)
 {
   if(btnsFreqRange[i].btnClicked())
   {
     maxFreq = btnsFreqRange[i].btnGetVal();
     btnsFreqRange[i].btnSetActive();
     btnsFreqRange[i].btnDisplay();
   }else
     btnsFreqRange[i].btnSetInactive();
 }
 
 for(int i=0; i<10; i++)
 {
   if(btnsIntensity[i].btnClicked())
   {
     sendOSCMsg((float)btnsIntensity[i].btnGetVal(), "/int");
     btnsIntensity[i].btnSetActive();
     btnsIntensity[i].btnDisplay();
   }else
     btnsIntensity[i].btnSetInactive();
 } 
}

void sendOSCMsg(float val, String name)
{
  OscMessage msg = new OscMessage(name);
  msg.add(val);
  oscSender.send(msg, oscDestination);
  println("sending: " + name + " " + val);
}

#2

looks like at any mouse click all buttons are deactivated, bad
( if anywhere on canvas, freq select window, or not this option group )

and on click on one button only this one is activated. good

OPTION GROUP need separate handling, example:


void mouseClicked(){
  if (mouseX >=0 && mouseX <= width && mouseY >= 80 && mouseY <= height-50)   {   //select freq and send it
    sendOSCMsg(freq, "/freq");
    drawFixed = mouseX;
  }

  //check if any btn ( OF THIS OPTION GROUP ) was clicked
  int thisone = -1;
  for (int i=0; i<3; i++) if ( btnsFreqRange[i].btnClicked() ) thisone = i;
  if (thisone > -1 ) {
    for (int i=0; i<3; i++) {
      if ( thisone == i ) {
        maxFreq = btnsFreqRange[i].btnGetVal();
        btnsFreqRange[i].btnSetActive();
        //kll btnsFreqRange[i].btnDisplay();
      } else   btnsFreqRange[i].btnSetInactive();
    }
  }

  //check if any btn ( OF THIS OPTION GROUP ) was clicked
  thisone = -1;
  for (int i=0; i<10; i++) if ( btnsIntensity[i].btnClicked() ) thisone = i;
  if (thisone > -1 ) {
    for (int i=0; i<10; i++) {
      if ( thisone == i ) {
        sendOSCMsg((float)btnsIntensity[i].btnGetVal(), "/int");
        btnsIntensity[i].btnSetActive();
        //kll btnsIntensity[i].btnDisplay();
      } else
        btnsIntensity[i].btnSetInactive();
    }
  }
  
  
}


#3

thanks! Would you say this is a correct approach or would you suggest re-writing my class in a different way?


#4

actually i would not know how to do the option group from inside the class,
so handling outside is ok, but there might be a better way for this…
can you experiment with G4P option group to get a idea,
http://www.lagers.org.uk/g4p/ref/classg4p__controls_1_1_g_toggle_group.html


possibly even check his source??