javaprocessingcontrol-p5

How to display a button with an image only in the desired tab?


I have OKNO1 and OKNO2, I want to show a button with an image strictly in OKNO1.

At the moment, the button with the image is shown globally. I used to use cp5.addButton and there I did it with .moveTo("okno1");

Now the image button uses OOP/Java. How to solve a tricky problem? What ways can you do the task. I think to use again void draw().

enter image description hereenter image description here

Complete code example:

import controlP5.*;
ControlP5 cp5;
ImageButton button;
Textlabel I;
Textlabel tempIn;

void setup() {
  size(700, 420, P3D);
  surface.setResizable(false);
  smooth();
  frameRate(30);
  cp5 = new ControlP5(this);

  PFont p = createFont("Times New Roman", 18);
  ControlFont font=new
    ControlFont(p);
  cp5.setFont(font);

  cp5.addTab("okno2")
    .setColorBackground(color(0, 160, 100))
    .setColorLabel(color(255))
    .setColorActive(color(255, 128, 0));

  cp5.getTab("default")
    .activateEvent(true)
    .setLabel("okno1")
    .setId(1);

  cp5.getTab("okno2")
    .activateEvent(true)
    .setId(2);

  tempIn = cp5.addTextlabel("Sostoyanie")
    .setText("1")
    .setFont(createFont("Times New Roman", 20))
    .setColor(color(0xffffff00))
    .setPosition(155, 35);

  I = cp5.addTextlabel("Impuls")
    .setText("2")
    .setPosition(155, 35)
    .setFont(createFont("Times New Roman", 20))
    .setColor(color(0xffffff00))
    .moveTo("okno2");

  int w = 99;
  int h = 25;
  button = new ImageButton(112, 137, w, h, 
    new PImage[]{
    loadImage("0.png"), // off
    loadImage("1.png"), // 10
    loadImage("2.png"), // 20
    loadImage("3.png"), // 30
    loadImage("4.png"), // 40
    loadImage("5.png"), // 50
    loadImage("6.png"), // 60
    });
}
void draw() {
  background(0);
  button.draw();
}
void mousePressed() {
  button.mousePressed(mouseX, mouseY);
  println(button.min);
}
PImage getImage(int w, int h, int c) {
  PImage img = createImage(w, h, RGB);
  java.util.Arrays.fill(img.pixels, c);
  img.updatePixels();
  return img;
}
class ImageButton {
  int min = 0;
  PImage[] stateImages;
  int stateIndex;
  int x, y;
  int w, h;
  String label = "ВЫКЛ";
  ImageButton(int x, int y, int w, int h, PImage[] stateImages) {
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.stateImages = stateImages;
  }
  void mousePressed(int mx, int my) {
    boolean isOver = ((mx >= x && mx <= x + w) &&
      (my >= y && my <= y + h) ); // check vertical
    if (isOver) {
      min += 10;
      stateIndex++;
      if (min>60) {
        min = 0; 
        stateIndex = 0;
        label = "ВЫКЛ";
      } else {
        label = min + " Мин";
      }
    }
  }
  void draw() {
    if (stateImages != null && stateIndex < stateImages.length) {
      image(stateImages[stateIndex], x, y, w, h);
    } else {
      println("error displaying button state image");
      println("stateImages: ");
      printArray(stateImages);
      println("stateIndex: " + stateIndex);
    }
}

Solution

  • Help others (including myself) help you:

    To help yourself always make sure you understand all your code completely:

    This will help you debug code in general. Also checkout Kevin Workman's Debugging tutorial.

    Regarding your issue: the button is rendered all the time in draw(). You want to only draw it when the first tab is active hence:

    e.g instead of button.draw() you'd use:

    if(cp5.getTab("default").isActive()){
        button.draw();
      }
    

    That will do the trick, but as you interface gets more complex, you may want group what's being drawn per tab. Here's an idea on how to organise for a UI with more controls per tab:

    Like so:

    void controlEvent(ControlEvent event) {
      // update current tab only if the current event comes from a tab (and not other controllers) 
      if(event.isTab()){
        currentTab = event.getId();
      }
    }
    

    The idea is controlEvent will get triggered when any ControlP5 component (controller) is clicked/updated. If it's a tab you can update currentTab to know in draw() which content to draw() using displayTabs():

    void displayTabs(){
      switch(currentTab){
        case 1:
          displayTab1();
          break;
        case 2:
          displayTab2();
          break;
      }
    }
    
    void displayTab1(){
      button.draw();
    }
    
    void displayTab2(){
      // render stuff for tab 2 only
    }
    

    So there's one switch with calls one function or another depending on the currentTab value. The advantage of doing things this was is that you can easily replicate another case for another tab in the future and each tab content is neatly compartmentalised.