Search code examples
javaswingalignmentjbutton

How to properly align a multiline text in a JButton?


I am trying to figure it out how to align some text in a JButton, but it seems to be more challenging than I thought it can be. In some ways I have tried to use HTML and JLabel, but had no luck with it. What I am trying to do, I want to simulate a keyboard key with letter centered and a digit on the right-top of it.

https://i.sstatic.net/dGnXx.png

JPanel panel = new JPanel();
LayoutManager layout = new FlowLayout();
panel.setLayout(layout);

String htmlContent = "<html><font align=right>10</font><br><center><font width=100>Some text<font></center><br><font height=20></font></html>";
String secondContent = "<html><sup>HTML</sup><br><font>Multi-line</font>";

JButton nextButton = new JButton(htmlContent);
nextButton.setForeground(new Color(0x000000));
nextButton.setBackground(new Color(0xffffff));
nextButton.setBorderPainted(false);
nextButton.setFocusPainted(false);
nextButton.setBounds(0, 0, 30, 25);
panel.add(nextButton);

JButton secondButton = new JButton(secondContent);
secondButton.setForeground(new Color(0xffffff));
secondButton.setBackground(new Color(0x0062ff));
secondButton.setBorderPainted(false);
secondButton.setFocusPainted(false);
panel.add(secondButton);

JLabel firstLabel = new JLabel("First");
firstLabel.setHorizontalTextPosition(JLabel.RIGHT);
firstLabel.setVerticalTextPosition(JLabel.TOP);
firstLabel.setSize(150,100);
JLabel secondLabel = new JLabel("So much text");
secondLabel.setHorizontalTextPosition(JLabel.CENTER);
secondLabel.setVerticalTextPosition(JLabel.CENTER);
secondLabel.setSize(100,100);

JButton thirdBtn = new JButton();
thirdBtn.setForeground(new Color(0x000000));
thirdBtn.setBackground(new Color(0xbdbdbd));
thirdBtn.setBorderPainted(false);
thirdBtn.setFocusPainted(false);
thirdBtn.add(firstLabel);
thirdBtn.add(secondLabel);
thirdBtn.setPreferredSize(new Dimension(200, 80));
panel.add(thirdBtn);

frame.getContentPane().add(panel, BorderLayout.CENTER);

So far here is the code I have tried to use to achieve this, but I can see no result of what I need, just cannot align the text to right or make it flow to there. Also tried using double labeled button, it seems that the labels cannot be aligned regarding each other. Is there a way to do that?

P.S. Forgot to mention, have tried to use align=right or align='right' or just 'right' in HTML tags, but none of these works

Results:

https://i.sstatic.net/EQcX3.png


Solution

  • Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Performing Custom Painting section.

    As I said in my comment, why not just create an image and place the image in a JButton.

    Here's the GUI I came up with.

    Example

    To create images for all your JButtons, just call the image creation method in a loop.

    Here's the complete runnable code.

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.RenderingHints;
    import java.awt.image.BufferedImage;
    
    import javax.swing.BorderFactory;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class JButtonImageExample implements Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new JButtonImageExample());
        }
    
        private BufferedImage image;
    
        public JButtonImageExample() {
            Font font = new Font(Font.DIALOG, Font.PLAIN, 36);
            this.image = createLetterImage(70, 70, font, 'G', 7);
        }
    
        @Override
        public void run() {
            JFrame frame = new JFrame("Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(createButtonPanel(), BorderLayout.CENTER);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private JPanel createButtonPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
    
            JButton button = new JButton(new ImageIcon(image));
            panel.add(button);
    
            return panel;
        }
    
        private BufferedImage createLetterImage(int width, int height, Font font,
                char letter, int value) {
            BufferedImage image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = (Graphics2D) image.getGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                    RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setFont(font);
    
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, width, height);
    
            g2d.setColor(Color.BLACK);
            String s = Character.toString(letter);
            Rectangle rect = new Rectangle(0, 0, width, height);
            drawCenteredString(g2d, s, rect, font);
    
            g2d.setColor(Color.BLUE);
            s = Integer.toString(value);
            drawRightAlignedString(g2d, s, width, font);
    
            g2d.dispose();
    
            return image;
        }
    
        private void drawRightAlignedString(Graphics2D g2d, String text, int width,
                Font font) {
            int pointSize = font.getSize() / 2;
            g2d.setFont(font.deriveFont((float) pointSize));
            FontMetrics metrics = g2d.getFontMetrics(g2d.getFont());
            int margin = 2;
            int x = width - metrics.stringWidth(text) - margin;
            int y = metrics.getAscent() - margin;
            g2d.drawString(text, x, y);
        }
    
        private void drawCenteredString(Graphics2D g2d, String text, Rectangle rect,
                Font font) {
            FontMetrics metrics = g2d.getFontMetrics(font);
            int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
            int y = rect.y + ((rect.height - metrics.getHeight()) / 2)
                    + metrics.getAscent();
            g2d.setFont(font);
            g2d.drawString(text, x, y);
        }
    
    }