Ensuring Responsive Text Size in Java Graphical Interface with Custom Buttons

35 views Asked by At

I would need help with a Java project, specifically regarding the graphical part. I have created a graphical object called RButton that allows me to create custom buttons. I display them on a grid using GridBagLayout and GridBagConstraints; however, I have a problem. When I resize my window slightly, the text completely disappears to become a tiny square where the text is unreadable, resulting in an application that is not truly responsive. How can I ensure that the text size is always adjusted accordingly?enter image description hereenter image description hereenter image description hereenter image description here

Here is the code for a button

package fr.riya.entity.graphic;

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import static java.awt.Font.PLAIN;

/**
 * The type R button.
 */
public class RButton extends JButton {
    private int width;
    private int height;
    private int coordX = 0;
    private int coordY = 0;
    private String title;
    private boolean isBordered = false;
    private boolean isHovered = false;
    private int curved = 10;

    /**
     * Instantiates a new RButton.
     *
     * @param x     the x
     * @param y     the y
     * @param w     the w
     * @param h     the h
     * @param title the title
     */
    public RButton(int x, int y, int w, int h, String title) {
        this.coordX = x;
        this.coordY = y;
        this.width = w;
        this.height = h;
        this.title = title;
        curved = 10;

        setBounds(x, y, w, h);
        setContentAreaFilled(false);
        setFocusPainted(false);
        setBorderPainted(false);
        setOpaque(false);
        setActionCommand(title);


        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                isHovered = true;
                repaint();
            }

            @Override
            public void mouseExited(MouseEvent e) {
                isHovered = false;
                repaint();
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g.create();
        g2.setColor(new Color(32, 25, 38));

        g2.fillRoundRect(0, 0, getWidth(), getHeight(), curved, curved);

        if(isBordered) {
            g2.setColor(new Color(0, 71, 79));
            g2.drawRoundRect(2, 2, getWidth()-3, getHeight()-3, curved, curved);
        } if(isHovered) {
            g2.setColor(new Color(255, 255, 255));
            g2.drawRoundRect(2, 2, getWidth()-3, getHeight()-3, curved, curved);
        }

        g2.setColor(Color.WHITE);
        Font font = new Font("Cabin", PLAIN, 48);
        g2.setFont(font);
        FontMetrics metrics = g2.getFontMetrics(font);
        g2.drawString(this.title, (getWidth() - metrics.stringWidth(this.title)) / 2,
                ((getHeight() - metrics.getHeight()) / 2) + metrics.getAscent());

        g2.dispose();
    }

    public String getTitle(){
        return this.title;
    }

    public void setCurved(int c){
        curved = c;
    }

    public void setBorder(boolean b) {
        isBordered = b;
    }
}

and here an exemple :

GridBagConstraints gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.gridheight = 1;
        gbc.anchor = CENTER;
        gbc.fill = NONE;
        gbc.weighty = 0;
        RButton profile = new RButton(0, 0, 256, 130, "Profile");
        profile.setPreferredSize(new Dimension(256, 130));
        profile.setCurved(0);
        add(profile, gbc);

        gbc.gridx = 1;
        RLine line = new RLine(0, 0, THICKNESS, 130, new Color(0, 71, 79));
        line.setPreferredSize(new Dimension(THICKNESS, 130));
        add(line, gbc);```

I tried to set a PreferedSize and think it is the problem. But if i don't use it, no button come out
1

There are 1 answers

0
MadProgrammer On

So one of the, few, things you're ignoring is the fact that the button will calculate its preferred size, in part, from the title text and font metrics, none of which you've actually taken into account with your "custom" workflow.

JButton already has a Font property, already supports "roll over" (or hover) and has a background color property, all of which, you ignore.

So, instead, you could actually just do something like...

public class RButton extends JButton {

    private int width;
    private int height;
    private int coordX = 0;
    private int coordY = 0;
    private String title;
    private boolean isBordered = false;
    private boolean isHovered = false;
    private int curved = 10;

    /**
     * Instantiates a new RButton.
     *
     * @param x the x
     * @param y the y
     * @param w the w
     * @param h the h
     * @param title the title
     */
    public RButton(int x, int y, int w, int h, String title) {
        this.coordX = x;
        this.coordY = y;
        this.width = w;
        this.height = h;
        this.title = title;
        curved = 10;

        // This is irrelevant and should otherwise be
        // ignored, the layout manager will make these
        // decisions for you, that's it's job
        //setBounds(x, y, w, h);
        setContentAreaFilled(false);
        setFocusPainted(false);
        setBorderPainted(false);
        setOpaque(false);
        setActionCommand(title);
        
        // I don't have your font, so I substituted my own
        setFont(new Font("Menlo", Font.PLAIN, 48));
        setForeground(Color.WHITE);
        setText(title);
        setRolloverEnabled(true);
        setBackground(new Color(32, 25, 38));
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setColor(getBackground());

        g2.fillRoundRect(0, 0, getWidth(), getHeight(), curved, curved);

        if (isBordered) {
            g2.setColor(new Color(0, 71, 79));
            g2.drawRoundRect(2, 2, getWidth() - 3, getHeight() - 3, curved, curved);
        }
        boolean isHovered = getModel().isRollover();
        if (isHovered) {
            g2.setColor(new Color(255, 255, 255));
            g2.drawRoundRect(2, 2, getWidth() - 3, getHeight() - 3, curved, curved);
        }

        g2.dispose();

        // This is a "trick" to ensure that the text is
        // rendered over our custom background, as the
        // test is rendered as part of paintComponent 
        // workflow
        super.paintComponent(g);
    }

    public String getTitle() {
        return this.title;
    }

    public void setCurved(int c) {
        curved = c;
        repaint();
    }

    public void setBorder(boolean b) {
        isBordered = b;
        repaint();
    }
}

Now, having said that, you're still going to have problems, as the font size is fixed, so the text will always be rendered at that size, regardless of what you do.

Dynamic font scaling is not simple and is an expensive operation, you could take a look at When I resize my App the Components get paints into the one who where already paint and it create a mess and Making text width flexible with ttf font for some ideas into how you might achieve this.