Ell
Ell

Reputation: 29

How to set background within the titled border?

I have a JLabel that I do setBackground(Color.WHITE) and setBorder(new CustomTitledBorder(Color.BLACK, "Some Text"). The white background from the JLabel is outside of the border bounds. I tried looking around and found this solution:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

public class TempFrame extends JFrame {

    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TempFrame frame = new TempFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TempFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(null);
        setContentPane(contentPane);

        var label = new MyLabel();
        label.setBounds(10, 10, 334, 65);
        getContentPane().add(label);

        JButton btnNewButton = new JButton("Click To Add Text");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                label.setText("String");
            }
        });
        btnNewButton.setBounds(127, 86, 89, 23);
        contentPane.add(btnNewButton);
    }

    private class MyLabel extends JLabel {

        public MyLabel() {
            
            setOpaque(true);
            setBorder(new CustomTitledBorder(Color.BLACK, "Title Here"));
            setBackground(Color.WHITE);
            
        }

/* Here is where I am having the problem */
//      @Override
//      protected void paintComponent(Graphics g) {
//          var insets = this.getBorder().getBorderInsets(this);
//          g.setColor(Color.WHITE);
//          g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right,
//                  getHeight() - insets.top - insets.bottom);
//      }

    }

    private class CustomTitledBorder extends TitledBorder {

        public CustomTitledBorder(Color color, String title) {
            super(new LineBorder(color), title);
            
        }

    }
}


This is without modifying the paintComponent() method Without modifying paintComponent()

This is what I want the paintComponent() method to do enter image description here

If I try to add text to it using setText("String");, this is the result. I can see some of my other components too somehow overlapping each other in that corner enter image description here

How do I make it so that it does not do that?

Upvotes: 1

Views: 654

Answers (2)

Olivier Faucheux
Olivier Faucheux

Reputation: 2606

Another solution if you don't want override the Label class: override the border itself – however, I have problems to obtain the background of the component's parent:

public class NonOpaqueTitledBorder extends TitledBorder {
    public NonOpaqueTitledBorder(final String title) {
        super(title);
    }

    private static Color getParentBackground(final Component c) {
        if (c instanceof JLabel) {
            return c.getParent().getParent().getBackground();
        } else if (c instanceof JTextField) {
            return c.getParent().getParent().getBackground();
        } else {
            return c.getParent().getBackground();
        }
    }

    @Override
    public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
        Insets borderInsets = this.getBorderInsets(c);
        g.setColor(getParentBackground(c));

        // top and bottom
        g.fillRect(x, y, width, borderInsets.top);
        g.fillRect(x, y + height - borderInsets.bottom, width, borderInsets.bottom);

        // left and right
        g.fillRect(x, y, borderInsets.left, height);
        g.fillRect(x + width - borderInsets.right, y, borderInsets.right, height);

        super.paintBorder(c, g, x, y, width, height);
    }
}

Upvotes: 0

camickr
camickr

Reputation: 324118

Based on the image provided it appears you want the background color of the parent panel to be used for the background of the border and provide a different background color for the remainder of the label.

So this means that you need to:

  1. keep the label transparent so the background of the parent is first painted
  2. paint the background of the label minus the area used by the Border
  3. paint the text of the label

So your custom label class should be:

private class MyLabel extends JLabel
{
    public MyLabel()
    {
        //setOpaque(true);
        setBorder(new CustomTitledBorder(Color.BLACK, "Title Here"));
        setBackground(Color.WHITE);
    }

  @Override
  protected void paintComponent(Graphics g)
  {
        var insets = this.getBorder().getBorderInsets(this);
        g.setColor(Color.WHITE);
        g.fillRect(insets.left, insets.top, getWidth() - insets.left - insets.right, getHeight() - insets.top - insets.bottom);

        super.paintComponent(g);
  }

}

Upvotes: 2

Related Questions