-1
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)

  • There are Unicode glyphs that are numbers within circles. Perhaps you could use those, drawn in red text. U+24FF and U+2776 to U+2784. – Tim Roberts Jul 07 '23 at 05:15
  • number will be dynamic, not known in advance – aksingh785 Jul 07 '23 at 05:16
  • If it is less than 20, the glyphs will work. If it can be larger, then it won't. – Tim Roberts Jul 07 '23 at 05:20
  • [Edit] your question and post the code that you tried. Are you using [JLabel](https://docs.oracle.com/javase%2Ftutorial%2F/uiswing/components/label.html) to display what appears in the image? It also sounds like there may be a different way to achieve what you are trying to do. Why do you need a red circle behind the number? – Abra Jul 07 '23 at 05:47
  • *I've issues with getting the circular background behind the number* - Use a JLabel with an Icon and text. See: https://stackoverflow.com/a/32700526/131872 for an example with a rectangular Icon. Just change the painting to be an oval. This approach would also work for a JButton. – camickr Jul 07 '23 at 19:23

1 Answers1

0

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();
        }

    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • How can I accommodate this without JPanel, in a button, details added in question – aksingh785 Jul 07 '23 at 10:52
  • That's a far more complex problem and one which `JButton` isn't well suited for – MadProgrammer Jul 07 '23 at 22:46
  • Thanks, Is it possible to add this dynamically, I'm trying to create animation out of it. – aksingh785 Jul 10 '23 at 16:04
  • That depends a lot on what you mean by “animation” - and all the code is dynamic – MadProgrammer Jul 10 '23 at 21:26
  • maybe hiding and showing the circle or changing the size/color just to make it noticeable – aksingh785 Jul 11 '23 at 07:50
  • Animation in Swing is not easy, good animation in Swing is hard, it's something you'd need to carefully design for. The layout managers don't tend to like you messing with things like the size/position of the components, for example, there are "cheats" you can do, but it's complicated. Changing the color or alpha is simple enough. If you don't mind getting your hands dirty, you could render the text yourself directly, this would allow you to do some scaling effects, but calculating the required size of the text is not a simple matter – MadProgrammer Jul 11 '23 at 21:47