1

I've created a custom border class where I fill a rectangle to act as a background for a component. Note that this border will have a more complex shape in the future, not just a simple rectangle.

When I add my border to a component, the text of the component will appear behind the border and make the text unreadable. (The result is depicted in the image below.)

Is there a way to draw the border below the text?

https://i.stack.imgur.com/Y9ehY.png

My border class:

public class CustomBorder extends AbstractBorder {
    private static final long serialVersionUID = 1L;

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(new Color(125, 125, 125, 255));
        g2d.fillRect(x - 10, y - 10, width + 20, height + 20);
    }

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

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

    @Override
    public boolean isBorderOpaque() {
        return super.isBorderOpaque();
    }
}

Main:

public static void main(String[] args) {
    JLabel label = new JLabel("JLabel text");
    label.setBorder(new CompoundBorder(new EmptyBorder(50, 20, 20, 20), new CustomBorder()));

    JFrame frame = new JFrame("");
    frame.setLayout(new FlowLayout());
    frame.setSize(200, 200);
    frame.add(label);
    frame.setVisible(true);
}

Edit: I should also note that I will be using this border to a chat program, which will be using bubble-shaped messages, so a colored square using setBackground() is a no-no.

Spitz
  • 79
  • 1
  • 3
  • 10

2 Answers2

3

See A Closer Look at the Paint Mechanism which explains how the painting is done. The border is painted after the text of the label is painted.

What exactly are you trying to do? Your border painting code doesn't make sense. You are trying to fill a rectangle equal to the width/height of the component + 20 pixels, which means you are trying to paint an area larger than the component.

If you are just trying to paint a background on a label then you can use:

label.setOpaque( true );
label.setBackground(...);

Edit: The code in this answer that was linked in the comment section below solved the problem.

Community
  • 1
  • 1
camickr
  • 321,443
  • 19
  • 166
  • 288
  • I'm trying to make a customized border for my components, which will act as chat messages and the border will be shaped like a speech bubble; I made a rectangle to shorten down the code. The reason behind the +20px is to make some space around the text. – Spitz Jan 27 '16 at 20:33
  • @Spitz Borders paint "around" a component. For what you're trying to do, you probably need to start with a base component which defines the shape you want to use, then add other components to it. You could have a look at [this](http://stackoverflow.com/questions/20505548/java-bubble-image-adapt-to-text-size/20508153#20508153) and [this](http://stackoverflow.com/questions/23355780/layering-text-over-jlabel/23355828#23355828) for example – MadProgrammer Jan 27 '16 at 21:13
  • `The reason behind the +20px is to make some space around the text.` - you need to set the BorderInsets to give space around the text. Check out: [Border Bubble](//http://stackoverflow.com/questions/15025092/border-with-rounded-corners-transparency) for an example of how you might create your speech bubble. – camickr Jan 27 '16 at 21:15
  • @camickr I tried to add 10 to every value of the returned `Insets` object in my overridden `getBorderInsets()` without any effect. Besides, is the thing what I did considered bad practice? – Spitz Jan 28 '16 at 10:03
  • 1
    @Spitz, Your code won't work so you need to start over. I gave you a link explaining why it won't work. A Swing component can only paint within the bounds of the component so you can't paint 20 pixel outside the component. I also gave you a link to a working example that you can customize for your exact requirements. – camickr Jan 28 '16 at 15:50
  • Okay, I managed to get my border to work properly, but it got messed up when I used a `CompoundBorder` to combine my border with an `EmptyBorder` in order to create some padding. After some experimenting I managed to get my desired padding by changing the values of `getBorderInsets()` and `paintBorder()` instead. I will accept your answer if you add the link you gave me, so other people easier can see the link easier. – Spitz Jan 30 '16 at 23:52
1

You could always use g2d.drawString(). However, if that is not to be utilised for some reason, you could just do:

JLabel l = new JLabel("foo");
l.setBackground(Color.GRAY);
l.setOpaque(true);
ruyili
  • 694
  • 10
  • 25
  • I doubt long lines of text will be wrapped if I draw it onto the component. – Spitz Jan 27 '16 at 22:41
  • Oh, I didn't know they were to be wrapped... I'll try to find another solution. EDIT: So just put the JLabel in front of the rectangle? – ruyili Jan 28 '16 at 00:55
  • Check this out: http://stackoverflow.com/questions/5853879/swing-obtain-image-of-jframe/5853992#5853992 – ruyili Jan 28 '16 at 01:02