Google Tag Manager

2020/08/31

Overlap the JLabel with a ribbon and slanted string in the corner

Code

class BadgeLabel extends JLabel {
  private final Color ribbonColor = new Color(0xAA_FF_64_00, true);
  private final String ribbonText;

  protected BadgeLabel(Icon image) {
    super(image);
    this.ribbonText = null;
  }

  protected BadgeLabel(Icon image, String ribbonText) {
    super(image);
    this.ribbonText = ribbonText;
  }

  @Override public void updateUI() {
    super.updateUI();
    setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
    setVerticalAlignment(SwingConstants.CENTER);
    setVerticalTextPosition(SwingConstants.BOTTOM);
    setHorizontalAlignment(SwingConstants.CENTER);
    setHorizontalTextPosition(SwingConstants.CENTER);
  }

  @Override protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.WHITE);
    g2.fill(getShape());
    super.paintComponent(g);

    if (ribbonText != null) {
      Dimension d = getSize();
      float fontSize = 10f;
      int cx = (d.width - (int) fontSize) / 2;
      double theta = Math.toRadians(45d);

      Font font = g2.getFont().deriveFont(fontSize);
      g2.setFont(font);
      FontRenderContext frc = new FontRenderContext(null, true, true);

      Shape ribbon = new Rectangle2D.Double(cx, -fontSize, d.width, fontSize);
      AffineTransform at = AffineTransform.getRotateInstance(theta, cx, 0);
      g2.setPaint(ribbonColor);
      g2.fill(at.createTransformedShape(ribbon));

      TextLayout tl = new TextLayout(ribbonText, font, frc);
      g2.setPaint(Color.WHITE);
      Rectangle2D r = tl.getOutline(null).getBounds2D();
      double dx = cx + (d.width - cx) / Math.sqrt(2d) - r.getWidth() / 2d;
      double dy = fontSize / 2d + r.getY();
      AffineTransform tx = AffineTransform.getTranslateInstance(dx, dy);
      Shape s = tl.getOutline(tx);
      g2.fill(at.createTransformedShape(s));
    }
    g2.dispose();
  }

  @Override public boolean isOpaque() {
    return false;
  }

  protected Shape getShape() {
    Dimension d = getSize();
    double r = d.width / 2d;
    return new RoundRectangle2D.Double(
        0d, 0d, d.width - 1d, d.height - 1d, r, r);
  }
}

Explanation

JLabel
  • Override JLabel#isOpaque() to make it transparent
  • Overrides JLabel#paintComponent(...) to draw a round rectangle for the background, then the original icon for `JLabel`, then the ribbon in the upper right corner, then the ribbon string
Ribbon
  • Create a Rectangle for the ribbon so that the lower left of the ribbon is positioned near the middle of the x axis of the parent JLabel
  • Rotate the lower left corner of the ribbon rectangle 45 degrees(Math.toRadians(45d)) about the origin
Ribbon string
  • Convert the Ribbon string to Shape using the TextLayout.getOutline(...) method
  • Rotate this Shape 45 degrees from its bottom left

References

No comments:

Post a Comment