Jonah Ajuzie
Jonah Ajuzie

Reputation: 31

Creating A Custom Shape For a JTextPane Border

Perfect Desired appearance

Undesirable Appearance

I am designing a chat application.

For the chat box which is a JTextPane, I used a custom shape other than the default rectangle shape as shown in the first image. But when this window which is a JInternalFrame is hovered over another window(JInternalFrame), the border line of the custom JTextPane show dragged lines as shown in the second image.

Please why is this happening?

What I did was to write a set JTextpane's border to a subclass of AbstractBorder. Attached too is the subclass of AbstractBorder used. However I've noticed that when I remove the graphic.setclip(area) and graphic.setclip(null) under the if(parent != null) block of paintBorder() method, the problem goes away.

How do I solve this line problem and still have my fancy text box?

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JPanel;
import javax.swing.border.AbstractBorder;

public class TextBubbleBorder1 extends AbstractBorder {

    private Color color;
    private int thickness = 4;
    private int radii = 8;
    private int pointerSize = 7;
    private Insets insets = null;
    private BasicStroke stroke = null;
    private int strokePad;
    private int pointerPad = 4;
    private boolean left = true;
    int xi, yi;
    RenderingHints hints;
    JPanel pane;
    boolean right;

    TextBubbleBorder1(
            Color color, int thickness, int radii, int pointerSize) {
        this.thickness = thickness;
        this.radii = radii;
        this.pointerSize = pointerSize;
        this.color = color;

        stroke = new BasicStroke(thickness);
        strokePad = thickness / 2;

        hints = new RenderingHints(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        int pad = radii + strokePad;
        int bottomPad = pad + pointerSize + strokePad;
        insets = new Insets(-2,16,0,0);
    }


    TextBubbleBorder1(
    Color color,int thickness,int radii,int pointerSize,bolean left, boolean right, int x, int y) {
        this(color, thickness, radii, pointerSize);
        this.left = left;
        this.xi = x;
        this.yi = y;
        this.right = right;

    }

    @Override
    public Insets getBorderInsets(Component c) {
        return insets;
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        return getBorderInsets(c);
    }

    @Override
    public void paintBorder(
            Component c,
            Graphics g,
            int x, int y,
            int width, int height) {

        Graphics2D g2 = (Graphics2D) g;

        int bottomLineY = height - thickness - pointerSize + 10 ;

        RoundRectangle2D.Double bubble = null;
        Area area = null;

        Polygon pointer = null;
        if(!right){

         bubble = new RoundRectangle2D.Double(
                10,
                0,               
                !left ? width-9 : width - 25,
                bottomLineY,
                radii,
                radii);
        area = new Area(bubble);
         pointer = new Polygon();
        if(!left){
            // left point
        pointer.addPoint(11, 3);
        pointer.addPoint(11, 14);
        pointer.addPoint(0, 8);
        }else{
        pointer.addPoint(width-17, 2);
        pointer.addPoint(width-23, 16);
        pointer.addPoint(width-5, 6);
        } 
        area.add(new Area(pointer));
        }else{
            bubble = new RoundRectangle2D.Double(
                0,
                -2,               
                width,
                bottomLineY+5,
                radii,
                radii);
        area = new Area(bubble);
        }



        g2.setRenderingHints(hints);

        // Paint the BG color of the parent, everywhere outside the clip
        // of the text bubble.
        Component parent  = c.getParent();
     if (parent!=null) {
           Color bg = parent.getBackground();
              Rectangle rect = new Rectangle(0,0,width, height);
              Area borderRegion = new Area(rect);
              borderRegion.subtract(area);
            g2.setClip(borderRegion);
            g2.setColor(bg);
            g2.fillRect(0, 0, width, height);
            g2.setClip(null);
       }
        g2.setColor(color);
        g2.setStroke(stroke);
        g2.draw(area);
    }

}

Upvotes: 1

Views: 327

Answers (1)

StanislavL
StanislavL

Reputation: 57421

You can store original clip and set it back

E.g.

Shape oldCLip=g2.getClip();
...your code here...
g2.setClip(oldClip);

Clip is not rectangle but could be custom shape. When you set it to null you destroy it for parent as well because Graphics instance goes from parent to children. So you should restore it properly.

Upvotes: 1

Related Questions