3

I'm using JFreeChart and I want to customise the ToolTip by creating my own Class which extends ChartPanel and override createToolTip().

static private class PrivateChartPanel extends ChartPanel{

    //constructors

    @Override
    public JToolTip createToolTip() {

        JToolTip jtt = super.createToolTip();

        jtt.setBackground(Color.WHITE);

        jtt.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));

        return jtt;

    }

}

The problem is at Border. It is not rounded on all corners.

tooltip-border-problem

Why it is not rounded on all corners and how I could done it?

P.S.: I created a new simple project

import java.awt.Color;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class HelloWorld {

  public static void main(String[] args) {

    JFrame a = new JFrame();

    a.setBounds(100, 100, 100, 100);
    a.setLayout(null);

    JPanel b = new JPanel();

    b.setBounds(5, 5, 50, 50);
    b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));

    a.add(b);

    a.setVisible(true);

  }

}

and Border of JPanel is with same problem. I'm using Java 10

KunLun
  • 3,109
  • 3
  • 18
  • 65
  • Does maybe the ChartPanel override the Border? Have you tried using the Border on other components? – camickr Oct 11 '18 at 14:52
  • @camickr I don't know what to say about `@Override Border`. I use `BorderFactory` from `javax.swing`. But I created a new simple project with [this code](https://www.tutorialspoint.com/tpcg.php?p=s4hlHj) and `Border` of `JPanel` is with same problem. P.S.: I use `Java10`. – KunLun Oct 11 '18 at 15:06
  • Post your code that demonstrates the problem in your question. Then we can copy/paste to see if we have the same problem or whether this could be a version/platform problem. – camickr Oct 11 '18 at 16:06
  • @camickr [here](https://www.tutorialspoint.com/tpcg.php?p=s4hlHj) is a sample which has the same problem, for me. – KunLun Oct 11 '18 at 16:22
  • The code should be posted with your question, not on another website. – camickr Oct 11 '18 at 17:10
  • @camickr now is ok? – KunLun Oct 11 '18 at 20:01
  • It doesn't work for me either using JDK8 on Windows 7. You can try creating your own Border. Check out: https://stackoverflow.com/questions/15025092/border-with-rounded-corners-transparency – camickr Oct 11 '18 at 21:00
  • Possible duplicate of [Border with rounded corners & transparency](https://stackoverflow.com/questions/15025092/border-with-rounded-corners-transparency) – Shahid Oct 12 '18 at 02:10

1 Answers1

6

The effect of rounded corners depends on the size of these rounded corners. In case of LineBorder, it is determined by the thickness property. This is how the relevant implementation code looks like:

int offs = this.thickness;
int size = offs + offs;
if (this.roundedCorners) {
    float arc = .2f * offs;
    outer = new RoundRectangle2D.Float(x, y, width, height, offs, offs);
    inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, arc, arc);
}
else {
    outer = new Rectangle2D.Float(x, y, width, height);
    inner = new Rectangle2D.Float(x + offs, y + offs, width - size, height - size);
}
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(outer, false);
path.append(inner, false);
g2d.fill(path);

So it differentiates between inner and outer corner, which is not much meaningful for a line size of one. But even worse, the outer corner size is just offs, which is identical to thickness (one in your case) and the size of the inner rounded corner is determined by arc, which is .2f * offs. For your thickness of one, the resulting inner corner size is 0.2. So it seems to be a pure coincidence (rounding issue of these two different corners) that we see an effect in the upper left corner, as even the bigger outer corner size of one is not enough to create a visible rounded effect.

Here is how it looks like with a thickness of 20, which results in an outer corner size of 20 and a whopping inner corner size of 4:

Screenshot with border thickness of 20

It don’t know which actual use case the Swing developers had in mind when they added the rounded corner support in this class. I can’t imagine any scenario where this strategy is useful.

Implementing a meaningful Border is not that hard. One possible implementation looks like:

public class RoundedLineBorder extends AbstractBorder {
    int lineSize, cornerSize;
    Paint fill;
    Stroke stroke;
    private Object aaHint;

    public RoundedLineBorder(Paint fill, int lineSize, int cornerSize) {
        this.fill = fill;
        this.lineSize = lineSize;
        this.cornerSize = cornerSize;
        stroke = new BasicStroke(lineSize);
    }
    public RoundedLineBorder(Paint fill, int lineSize, int cornerSize, boolean antiAlias) {
        this.fill = fill;
        this.lineSize = lineSize;
        this.cornerSize = cornerSize;
        stroke = new BasicStroke(lineSize);
        aaHint = antiAlias? RenderingHints.VALUE_ANTIALIAS_ON: RenderingHints.VALUE_ANTIALIAS_OFF;
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        int size = Math.max(lineSize, cornerSize);
        if(insets == null) insets = new Insets(size, size, size, size);
        else insets.left = insets.top = insets.right = insets.bottom = size;
        return insets;
    }

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Graphics2D g2d = (Graphics2D)g;
        Paint oldPaint = g2d.getPaint();
        Stroke oldStroke = g2d.getStroke();
        Object oldAA = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
        try {
            g2d.setPaint(fill!=null? fill: c.getForeground());
            g2d.setStroke(stroke);
            if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aaHint);
            int off = lineSize >> 1;
            g2d.drawRoundRect(x+off, y+off, width-lineSize, height-lineSize, cornerSize, cornerSize);
        }
        finally {
            g2d.setPaint(oldPaint);
            g2d.setStroke(oldStroke);
            if(aaHint != null) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldAA);
        }
    }
}

Now, when I change the line

b.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1, true));

in your example to

b.setBorder(new RoundedLineBorder(Color.BLACK, 1, 10, true));

I get

Screenshot with custom border

Holger
  • 285,553
  • 42
  • 434
  • 765