# Tooltip with ControlP5

**URL:** <https://discourse.processing.org/t/tooltip-with-controlp5/37917>\
**Category:** Libraries\
**Created:** [July 11, 2022, 7:24am UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917 "2022-07-11T07:24:08Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ghostsss](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/ghostsss/32/16483_2.png) [@Ghostsss](https://discourse.processing.org/u/Ghostsss)\
**Post date:** [July 11, 2022, 7:24am UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/1 "2022-07-11T07:24:08Z")

</div>

I want to add tooltip to GUI built using ControlP5.  
I found that some old examples (from around 2011) of tooltip in ControlP5 examples say that tooltip is not working as of now.

I want to know if it is still not working in 2022 ?  
And if not, is there anyway to implement tooltip ?

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 11, 2022, 1:48pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/2 "2022-07-11T13:48:18Z")

</div>

My Examples/ControlP5/Tooltip demo doesn’t work either. The following Swing button has a workable tooltip.

```auto
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

javax.swing.JFrame frame;
java.awt.Canvas canvas;

void buildWnd() {
  JButton btn = new JButton("Press me.");
  btn.setBounds(50, 100, 100, 30);
  btn.setToolTipText("Push Button");
  frame.add(btn);
  // ****Action**** //
  btn.addActionListener( new ActionListener() {
    void actionPerformed(ActionEvent actionEvent) {
      println("Button was pressed.");
    }
  });
  btn.repaint();
}

void setup() {
  frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
  canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
  frame.setBounds(500, 300, 300, 300);
  frame.remove(canvas);

  javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      buildWnd(); // Builds components on EventDispatchThread
    }
  });
}

```

---

<div class="post-metadata">

**Author:** ![Ghostsss](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/ghostsss/32/16483_2.png) [@Ghostsss](https://discourse.processing.org/u/Ghostsss)\
**Post date:** [July 14, 2022, 10:39am UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/3 "2022-07-14T10:39:43Z")

</div>

I am getting following error while running this in Processing 3.5.4. Can you help with this.  
Error: Cannot reduce the visibility of the inherited method from ActionListener

By the way, can it be used to display tooltip on GUI built using ControlP5 ?  
(Sorry, I am new to java.)

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [July 14, 2022, 12:50pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/4 "2022-07-14T12:50:26Z")

</div>

> [@Ghostsss](#):
>
> Error: Cannot reduce the visibility of the inherited method from ActionListener

Explicitly declare affected method as `public`:

> **[public / Reference](https://processing.org/reference/public.html)**
>
> Keyword used to provide other classes access the fields and methods within a class. The public keyword is used before a field or method that you want to make available. In Processing, all field…

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 14, 2022, 1:14pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/5 "2022-07-14T13:14:11Z")

</div>

@GoToLoop has the solution. Add the word ‘public’ in front of ‘actionPerformed’:

```auto
public void actionPerformed(ActionEvent actionEvent) {
      println("Button was pressed.");
    }

```

To the best of my knowledge I don’t think you can add it to a ControlP5 control; I think you would need to contact the author.

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [July 14, 2022, 1:34pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/6 "2022-07-14T13:34:22Z")

</div>

> [@svan](#):
>
> Add the word `public` in front of **actionPerformed()**:

In general PDE’s preprocessor is able to automatically prefix methods w/ access keyword [`public`](https://processing.org/reference/public.html).

But b/c the [functional `interface`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/FunctionalInterface.html) [ActionListener](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/event/ActionListener.html) is having its method [**actionPerformed()**](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/event/ActionListener.html#actionPerformed(java.awt.event.ActionEvent)) being implemented via anonymous instantiation the preprocessor fails to detect that it’s a method.

However, if we move the [ActionListener](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/event/ActionListener.html) instantiation outside **buildWnd()** and assign it to a “global” variable, PDE’s preprocessor will be able to prefix **actionPerformed()** w/ keyword [`public`](https://processing.org/reference/public.html):

```java
static final ActionListener BUTTON_EVENT = new ActionListener() {
  void actionPerformed(final ActionEvent evt) { // no explicit public needed!
    println(evt);
  }
};

final Runnable createButton = new Runnable() {
  void run() { // no explicit public needed!
    buildWnd();
  }
};

```

```auto
btn.addActionListener(BUTTON_EVENT);

```

```auto
SwingUtilities.invokeLater(createButton);

```

Same for method [**run()**](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runnable.html#run()) from [functional `interface`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/FunctionalInterface.html) [Runnable](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runnable.html).

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 14, 2022, 1:44pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/7 "2022-07-14T13:44:56Z")

</div>

I’m sure you’re correct, but this runs in 3.5.4 without error on my system:

```auto
  btn.addActionListener( new ActionListener() {
    public void actionPerformed(ActionEvent actionEvent) {
      println("Button was pressed.");
    }
  });

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [July 14, 2022, 1:49pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/8 "2022-07-14T13:49:14Z")

</div>

> [@svan](#):
>
> , but this runs in 3.5.4 without error on my system:

Yes, after you explicitly declare method [**actionPerformed()**](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/event/ActionListener.html#actionPerformed(java.awt.event.ActionEvent)) as [`public`](https://processing.org/reference/public.html)! 😉

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 14, 2022, 2:06pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/9 "2022-07-14T14:06:35Z")

</div>

Yes, but that’s different from what you posted (and a lot easier!). I normally do all my testing in the latest version of Processing 4.0b8 where it is not a problem (I know you like old stuff).

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [July 14, 2022, 2:15pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/10 "2022-07-14T14:15:29Z")

</div>

> [@svan](#):
>
> … (and a lot easier!)…

Of course just adding `public` is indeed a lot easier!

I was just making a point about PDE’s preprocessor failing to automatically prefix `public` in this particular anonymous instantiation edge case.

My example is a boilerplate workaround to make PDE’s preprocessor finally be able to detect that both **actionPerformed()** & **run()** are methods and have keyword `public` automatically applied to them behind-the-scene.

> [@svan](#):
>
> … (I know you like old stuff).

As I already had mentioned on a previous topic, after P4 reaches a stable release & folks here stop creating topics about P4 bugs every single day, I’ll happily install it in my computer, as I did to all the other major releases!

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 14, 2022, 2:20pm UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/11 "2022-07-14T14:20:12Z")

</div>

I never would have figured that out on my own, so I greatly appreciate your help and insight. Thanks.

---

<div class="post-metadata">

**Author:** ![Ghostsss](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/ghostsss/32/16483_2.png) [@Ghostsss](https://discourse.processing.org/u/Ghostsss)\
**Post date:** [July 15, 2022, 3:34am UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/12 "2022-07-15T03:34:53Z")

</div>

Thank you both of you for the input.

By the way, I was going through ControlP5 examples.  
And I found Canvas example. It was doing something close to tooltip.

So I modified it to do tooltip.  
Kindly check it out and give feedback.

will this kind of implementation make the program run slow ? (if I do for 20-30 buttons?)  
is there a better way of implementing this ?

```auto
import controlP5.*;

ControlP5 cp5;
Button b1;

ControlWindow controlWindow;

Canvas cc;

// MyCanvas, your Canvas render class
class MyCanvas extends Canvas {

  int y;
  int mx = 0;
  int my = 0;
  long count;
  int mouseStopDelay = 20;
  public void setup(PGraphics pg) {
    y = 200;
  }  

  public void update(PApplet p) {
    mx = p.mouseX;
    my = p.mouseY;
  }

  public void draw(PGraphics pg) {
    // renders a square with randomly changing colors
    // make changes here.
    if(checkMouseNotMoving()){
      if(checkMouseOverController(b1)){
        pg.fill(100);
        pg.rect(mouseX, mouseY, 240, 30);
        pg.fill(255);
        pg.text("This toottip text is drawn by MyCanvas", mouseX+20,mouseY+20);
      }
    }
  }
  
  boolean checkMouseOverController(Button b){
    boolean result=false;
    float[] position =b.getPosition();
    boolean xCheck = (mouseX>position[0] && mouseX < position[0]+b.getWidth());
    boolean yCheck = (mouseY>position[1] && mouseY < position[1]+b.getHeight());
    
    if(xCheck && yCheck)
      result = true;
    return result;
  }
  
  boolean checkMouseNotMoving(){
    boolean result=false;
    if(mouseX==pmouseX && mouseY==pmouseY){
       if(count>mouseStopDelay){
         result = true;
       }else{
         count++;
       }
    }else{
      count=0;
      result = false;
    }
    return result;
  }
}

void setup() {
  size(400, 400);
  frameRate(30);
  cp5 = new ControlP5(this);

  // create a control window canvas and add it to
  // the previously created control window.  
  cc = new MyCanvas();
  //cc.pre(); // use cc.post(); to draw on top of existing controllers.
  cc.post(); // use cc.post(); to draw on top of existing controllers.
  cp5.addCanvas(cc); // add the canvas to cp5
  b1=cp5.addButton("Hello").setPosition(50,50).setSize(100,100);
}

void draw() {
  background(250);
  fill(60);
  rect(100, 100, 200, 200);
}

```

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [July 15, 2022, 5:26am UTC](https://discourse.processing.org/t/tooltip-with-controlp5/37917/13 "2022-07-15T05:26:36Z")

</div>

Looks like a creative and reasonable way to solve your problem. The following code will create a button grid of 25 buttons for you to practice on and answer the question whether it can handle the load. Runs in 4.0b8; not tested in 3.5.4 but should work ok.

```auto
import controlP5.*;

ControlP5 cp5;
final int rows = 5;
final int cols = 5;

final int _btnGridX = 40;
final int _btnGridY = 40;
final int _btnW = 100;
final int _btnH = 100;

Button[] btn = new Button[rows*cols];
color BLUE = color(64,124,188);

void btnGrid() {
  int left = 0;
  int top = 0;
  int vg = 30; // Space between cols (vert.gutter)
  int hg = 30; // Space between rows (horz.gutter)
  int id = 0;
  
  for (int k = 0; k < cols; k++) {
    for (int j = 0; j < rows; j++) {
      left = _btnGridX + j * (_btnW + vg);
      top = _btnGridY + k * (_btnH + hg);      
      btn[id]= cp5.addButton(str(id)).setPosition(left,top).setSize(_btnW,_btnH);
      id++;
    }
  } 
}

void setup() {
  size(720,720);
  background(BLUE);
  cp5 = new ControlP5(this);
  btnGrid();
}

void draw() {
  
}

```
