Закругленный LineBorder - не все углы скруглены - PullRequest
0 голосов
/ 11 октября 2018

Я использую JFreeChart и хочу настроить ToolTip, создав свой собственный Class, который расширяет ChartPanel и переопределяет 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;

    }

}

Проблема вBorder.Он не закруглен по всем углам.

tooltip-border-problem

Почему он не закруглен по всем углам и как я мог это сделать?

PS: я создал новый простой проект

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);

  }

}

и Border of JPanel с той же проблемой.Я использую Java 10

1 Ответ

0 голосов
/ 12 октября 2018

Эффект закругленных углов зависит от размера этих закругленных углов.В случае LineBorder это определяется свойством thickness.Вот как выглядит соответствующий код реализации:

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);

Таким образом, он различает внутренний и внешний угол, что не имеет большого значения для размера строки, равного единице.Но что еще хуже, размер внешнего угла составляет всего offs, что идентично thickness (в вашем случае - одному), а размер внутреннего закругленного угла определяется как arc, что составляет .2f * offs.Для вашего thickness единицы результирующий размер внутреннего угла равен 0.2.Похоже, что это чистое совпадение (проблема округления этих двух разных углов), что мы видим эффект в верхнем левом углу, так как даже больший размер внешнего угла, равный единице, недостаточен для создания видимого закругленного эффекта.

Вот как это выглядит с thickness из 20, что приводит к размеру внешнего угла 20 и огромному размеру внутреннего угла 4:

Screenshot with border thickness of 20

Не известно, какой фактический вариант использования разработчики Swing имели в виду, когда добавляли поддержку закругленных углов в этом классе.Я не могу представить себе сценарий, в котором эта стратегия будет полезна.

Реализация значимого Border не так уж и сложна.Одна из возможных реализаций выглядит следующим образом:

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);
        }
    }
}

Теперь, когда я изменяю строку

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

в вашем примере на

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

, я получаю

Screenshot with custom border

...