Search code examples
javaswingjlabel

Java swing text with circular background


package test.client.swing.machine.view;

import java.awt.*;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

import test.client.swing.machine.view.ImageFactory.BorderType;

import static test.client.swing.machine.view.ComponentNameConstants.LABEL_VALUE_BUTTON_LABEL;
import static test.client.swing.machine.view.ComponentNameConstants.LABEL_VALUE_BUTTON_VALUE;


public class LabelValueButton extends SimpleGraphicButton {

    protected final JLabel left = new JLabel();
    protected final JLabel middle = new JLabel();
    protected final JLabel right = new JLabel();
    protected String label;
    protected Object value;

    public LabelValueButton(ImageFactory imageFactory, String label, Integer count, Object value, Border border,
        String imageNamePattern, BorderType bType, int width) {
        super(imageFactory);
        try {
            loadDynamicImages(imageNamePattern, bType, width);
        } catch (IllegalArgumentException e) {
            loadStandardImages(imageNamePattern);
        }
        setBorder(border);
        init(label, value, count);
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
        left.setText(label);
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
        right.setText(String.valueOf(value));
    }

    @Override
    public void setForeground(Color c) {
        super.setForeground(c);
        if (left != null) {
            left.setForeground(c);
        }
        if (right != null) {
            right.setForeground(c);
        }
        // repaint anscheinend nicht nötig
        // repaint();
    }

    @Override
    public void setFont(Font f) {
        super.setFont(f);
        if (left != null) {
            left.setFont(f);
        }
        if (right != null) {
            right.setFont(f);
        }
    }

    @Override
    public Font getFont() {
        return left != null ? left.getFont() : super.getFont();
    }

    protected void init(String label, Object value, Integer count) {

        CustomLabel circularText = new CustomLabel();
        circularText.setText("100");
        circularText.setForeground(Color.WHITE);
        circularText.setFont(circularText.getFont().deriveFont(Font.BOLD, 48 f));
        add(circularText);

        setLabel(label);
        setValue(value);
        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        if (getComponentOrientation().isHorizontal()) {
            //          add(Box.createHorizontalStrut(5));
            add(left);
            add(Box.createGlue());
            add(right);
            //          add(Box.createHorizontalStrut(15));

            left.setAlignmentY(0.5 f);
            right.setAlignmentY(0.5 f);
        } else {
            //          add(Box.createVerticalStrut(5));
            add(left);
            add(Box.createVerticalGlue());
            add(right);
            //          add(Box.createVerticalStrut(15));
        }
        left.setFont(Constants.getFontBold());
        left.setName(LABEL_VALUE_BUTTON_LABEL);
        right.setFont(Constants.getFontBoldMedium());
        right.setName(LABEL_VALUE_BUTTON_VALUE);
    }
}

I've to add the number in the middle JLabel, but not able

I'm pretty new to Java swing and trying to design a component where the text has a circular background. Something like in the image

enter image description here

I've issues with getting the circular background behind the number. Also the circle would be aligned right if there's not extra info, but will move to left if there's extra info present as in second image.

I tried with having the image as part of the red circle but that seems to overcomplicate thing as I've to overlay text on top and also the element position is not fixed (moves to left if more content is present)


Solution

  • A "simple" solution would be to paint a circle behind a JLabel

    Start by having a look at:

    for more details.

    enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagLayout;
    import java.awt.RenderingHints;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    
    public class Test {
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
    
                    JPanel content = new JPanel(new GridBagLayout());
                    content.setBorder(new EmptyBorder(32, 32, 32, 32));
    
                    CircularText circularText = new CircularText();
                    circularText.setText("100");
                    circularText.setForeground(Color.WHITE);
                    circularText.setFont(circularText.getFont().deriveFont(Font.BOLD, 48f));
    
                    content.add(circularText);
    
                    frame.add(content);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class CircularText extends JPanel {
    
            private JLabel label = new JLabel();
    
            public CircularText() {
                label.setFont(getFont());
                label.setForeground(getForeground());
                setOpaque(false);
                setBackground(Color.RED);
                setLayout(new GridBagLayout());
                setBorder(new EmptyBorder(8, 8, 8, 8));
                add(label);
            }
    
            public void setText(String text) {
                label.setText(text);
            }
    
            public String getText() {
                return label.getText();
            }
    
            @Override
            public void setFont(Font font) {
                super.setFont(font);
                if (label != null) {
                    label.setFont(font);
                }
            }
    
            @Override
            public void setForeground(Color fg) {
                super.setForeground(fg);
                if (label != null) {
                    label.setForeground(fg);
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                Dimension size = super.getPreferredSize();
                int max = Math.max(size.width, size.height);
                return new Dimension(max, max);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                g2d.setColor(getBackground());
                int size = Math.min(getWidth(), getHeight());
                int x = (getWidth() - size) / 2;
                int y = (getHeight() - size) / 2;
                g2d.fillOval(x, y, size, size);
                g2d.dispose();
            }
    
        }
    }
    

    Now remember, if you want text added either side, you're going to need to make use of suitable layout manager to manage the individual components, something like GridBagLayout might work well, for example...

    enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.RenderingHints;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    
    public class Test {
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
    
                    JPanel content = new JPanel(new GridBagLayout());
                    content.setBorder(new EmptyBorder(32, 32, 32, 32));
    
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.insets = new Insets(0, 4, 0, 4);
    
                    content.add(new JLabel("Some text"), gbc);
    
                    CircularText circularText = new CircularText();
                    circularText.setText("100");
                    circularText.setForeground(Color.WHITE);
    
                    content.add(circularText, gbc);
    
                    content.add(new JLabel("some more info"), gbc);
    
                    frame.add(content);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class CircularText extends JPanel {
    
            private JLabel label = new JLabel();
    
            public CircularText() {
                label.setFont(getFont());
                label.setForeground(getForeground());
                setOpaque(false);
                setBackground(Color.RED);
                setLayout(new GridBagLayout());
                setBorder(new EmptyBorder(8, 8, 8, 8));
                add(label);
            }
    
            public void setText(String text) {
                label.setText(text);
            }
    
            public String getText() {
                return label.getText();
            }
    
            @Override
            public void setFont(Font font) {
                super.setFont(font);
                if (label != null) {
                    label.setFont(font);
                }
            }
    
            @Override
            public void setForeground(Color fg) {
                super.setForeground(fg);
                if (label != null) {
                    label.setForeground(fg);
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                Dimension size = super.getPreferredSize();
                int max = Math.max(size.width, size.height);
                return new Dimension(max, max);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                g2d.setColor(getBackground());
                int size = Math.min(getWidth(), getHeight());
                int x = (getWidth() - size) / 2;
                int y = (getHeight() - size) / 2;
                g2d.fillOval(x, y, size, size);
                g2d.dispose();
            }
    
        }
    }
    

    How can I accommodate this without JPanel, in a button, details added in question

    First, don't update the question after the fact, it tends to void any previously provided answer, better to ask a new question with the "extra" details.

    Second JButton is a component/container, my first thought would be to try and add a component to the button itself. If that doesn't work, then you're in for a world of pain, as about the only other choice would be to use a custom look and feel delegate instead.

    Lucky for you, adding a component to a JButton seems to work...

    enter image description here

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.RenderingHints;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    
    public class Test {
        public static void main(String[] args) {
            new Test();
        }
    
        public Test() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    JPanel contentPane = new JPanel(new GridBagLayout());
                    contentPane.setBorder(new EmptyBorder(32, 32, 32, 32));
                    frame.setContentPane(contentPane);
    
                    JPanel buttonContent = new JPanel(new GridBagLayout());
                    buttonContent.setOpaque(false);
    
                    GridBagConstraints gbc = new GridBagConstraints();
                    gbc.insets = new Insets(0, 4, 0, 4);
    
                    buttonContent.add(new JLabel("Some text"), gbc);
    
                    CircularText circularText = new CircularText();
                    circularText.setText("100");
                    circularText.setForeground(Color.WHITE);
    
                    buttonContent.add(circularText, gbc);
    
                    buttonContent.add(new JLabel("some more info"), gbc);
    
                    JButton btn = new JButton();
                    btn.add(buttonContent);
    
                    frame.add(btn);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class CircularText extends JPanel {
    
            private JLabel label = new JLabel();
    
            public CircularText() {
                label.setFont(getFont());
                label.setForeground(getForeground());
                setOpaque(false);
                setBackground(Color.RED);
                setLayout(new GridBagLayout());
                setBorder(new EmptyBorder(8, 8, 8, 8));
                add(label);
            }
    
            public void setText(String text) {
                label.setText(text);
            }
    
            public String getText() {
                return label.getText();
            }
    
            @Override
            public void setFont(Font font) {
                super.setFont(font);
                if (label != null) {
                    label.setFont(font);
                }
            }
    
            @Override
            public void setForeground(Color fg) {
                super.setForeground(fg);
                if (label != null) {
                    label.setForeground(fg);
                }
            }
    
            @Override
            public Dimension getPreferredSize() {
                Dimension size = super.getPreferredSize();
                int max = Math.max(size.width, size.height);
                return new Dimension(max, max);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
                g2d.setColor(getBackground());
                int size = Math.min(getWidth(), getHeight());
                int x = (getWidth() - size) / 2;
                int y = (getHeight() - size) / 2;
                g2d.fillOval(x, y, size, size);
                g2d.dispose();
            }
    
        }
    }