When I resize my App the Components get paints into the one who where already paint and it create a mess

38 Views Asked by At

When I resize my app the Jtextfields before the resizement get paint over and it creates an huge mess enter image description here My code is simple I am trying to create a grid from an existing 2d array with the numbered centered in the grid like sudoku but when I resize my app the application it makes this mess here is my code:

package graphics;
import java.awt.*;

import javax.swing.JPanel;
import javax.swing.JTextField;
public class Table  {
    int currentX;
    int currentY;
    final Color currrentColor = Color.yellow;
    final Color pasteColor = Color.red;
    int[][] array;
    int[][] selectedCase;
    int selectedSize;
    TableRepresentation tab;
    void setRepresentation(Color backgroundColor, int width, int height) 
    {
       tab = new TableRepresentation(backgroundColor,width,height);
    }
    JPanel getRepresentation() 
    {
        
        return tab;
    }
    public Table(int[][] array)
    {
        this.array = array;
        selectedCase = new int[2][array.length * array[0].length];
        currentX = 0;
        currentY = 0;
        selectedSize = 0;
        updateCase(currentX , currentY);
    }
    public void updateCase(int x , int y) {
        currentX = x;
        currentY = y;
        selectedCase[0][selectedSize] = x;
        selectedCase[1][selectedSize] = y;
        selectedSize++;
    }
    private class TableRepresentation extends JPanel {
        double width;
        double height;
        Dimension ceil;
        TableRepresentation(Color backgroundColor, int width, int height){
            setSize(width, height);
            setBackground(backgroundColor);
            this.width = (double) width / array[0].length - 3;
            this.height = (double) height / array.length - 3;
            ceil = new Dimension((int)this.width - 2,(int)this.height - 2);
            
        }
        
        void createGrid(Graphics2D g2d) {
            g2d.drawRect(0,0,getWidth(), getWidth());
            for (int i = 1; i <= array[0].length ; i++) 
            {
                if (i == 1) 
                {
                    g2d.drawLine((5+(int) width) * i,0,(5+(int) width) * i,getWidth());
                }
                g2d.drawLine((4+(int) width) * i,0,(4+(int) width) * i,getWidth());
            }
            for (int i = 1; i < array[0].length ; i++) 
            {
                if (i == 1) 
                {
                    g2d.drawLine(0,((int) height + 5) * i,getHeight(),((int) height + 5) * i);
                }
                g2d.drawLine(0,((int) height + 4) * i,getHeight(),((int) height + 4) * i);
            }
            
        }
        Point getCeilAtLocation(int x, int y) {
            return new Point(3 + ((int) width + 3) * x,(3 + ((int) height + 3) * y));
        }
        JTextField setAtributes() {
            JTextField text = new JTextField();
            text.setSize(ceil);
            text.setBorder(null);
            text.setEditable(false);
            text.setFocusable(false);
            text.setForeground(Color.white);
            text.setBackground(Color.BLACK);
            text.setFont(new Font("Arial", Font.PLAIN,(int) width - 10));
            text.setHorizontalAlignment(JTextField.CENTER);
            
            return text;
        }
        void createNumbers()
        {
            
            JTextField text = null;
     
            for (int i = 0; i < array.length; i++) 
            {
                for (int j = 0; j < array[0].length; j++) 
                {
                    text = setAtributes();
                    text.setText(Integer.toString(array[i][j]));
                    text.setLocation(getCeilAtLocation(j,i));
                    add(text, -1);
                    text.setVisible(true);
                }
                
            }
            
        }
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.white);
            Stroke basic = new BasicStroke(3);
            g2d.setStroke(basic);
            createGrid(g2d);
            createNumbers();
            
        }
    }
}

How can I stop the textfields to get paint over please help

1

There are 1 best solutions below

2
MadProgrammer On

Your core problem is you're trying to add more components to the UI within a paint pass. This is not what you should be doing at this phase of the program, and even if you could, you'd need to remove the old components first.

Instead, start with some base properties. For example, set the initial font size to something sensible (or use the default font size of the text fields), then use an appropriate layout manager to handle the actual sizing/positing of the components and forget about the "width"/"height" of the "squares".

If the "width" & "height" are important, then I'd consider starting with a custom component and override it's getPreferredSize method with these values and add a single JTextField to it (maybe using a BorderLayout).

Now, the next problem is the font size, there is a significant difference between a fonts "point size" and it's pixel size, which should also include it's width and height of the text been rendered.

What you need to do, is when the component is resized, is calculate the desired "cell size", calculate the largest piece of text you need to render and then increase or decrease the point size until that piece of text fits within the bounds of the cell ... easy

enter image description here

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<JTextField> fields = new ArrayList<>(9);
        private Font textFont = new Font("Arial", Font.PLAIN, 48);

        public TestPane() {
            setBackground(Color.BLACK);
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridLayout(3, 3, 8, 8));
            for (int index = 0; index < 3 * 3; index++) {
                JTextField textField = makeTextField();
                fields.add(textField);
                textField.setText(Integer.toString(index));
                add(textField);
            }

            addComponentListener(new ComponentAdapter() {
                @Override
                public void componentResized(ComponentEvent e) {
                    Insets insets = getInsets();
                    int width = getWidth() - (insets.left + insets.right);
                    int height = getHeight() - (insets.top + insets.bottom);

                    width -= 2 * 8; // (numberOfColumns) - 1 * horizontalGap
                    height -= 2 * 8; // (numberOfRows) - 1 * verticalGap

                    double colWidth = width / 3;
                    double rowHeight = height / 3;

                    System.out.println("Cell = " + colWidth + "x" + rowHeight);

                    FontMetrics fm = getFontMetrics(textFont);
                    String biggestText = "";
                    int maxWidth = 0;
                    for (JTextField field : fields) {
                        int textWidth = fm.stringWidth(field.getText());
                        if (textWidth > maxWidth) {
                            maxWidth = textWidth;
                            biggestText = field.getText();
                        }
                    }

                    int textWidth = fm.stringWidth(biggestText);
                    int textHeight = fm.getHeight();

                    if (textWidth > colWidth || textHeight > rowHeight) {
                        // Reduce the font size
                        textFont = reduceFontPointToFit(biggestText, colWidth, rowHeight);
                    } else if (textWidth < colWidth || textHeight < rowHeight) {
                        // Increase the font size
                        textFont = increaseFontPointToFit(biggestText, colWidth, rowHeight);
                    }

                    for (JTextField field : fields) {
                        field.setFont(textFont);
                    }
                }
            });
        }

        protected Font reduceFontPointToFit(String text, double targetWidth, double targetHeight) {
            int pointSize = textFont.getSize();
            FontMetrics fm = getFontMetrics(textFont);
            Font font = textFont;
            do {
                pointSize -= 2;
                font = new Font("Arial", Font.PLAIN, pointSize);
                fm = getFontMetrics(font);
            } while (pointSize > 5 && fm.stringWidth(text) > targetWidth && fm.getHeight() > targetHeight);
            return font;
        }

        protected Font increaseFontPointToFit(String text, double targetWidth, double targetHeight) {
            int pointSize = textFont.getSize();
            FontMetrics fm = getFontMetrics(textFont);
            Font font = textFont;
            do {
                pointSize += 2;
                font = new Font("Arial", Font.PLAIN, pointSize);
                fm = getFontMetrics(font);
            } while (pointSize < 256 && fm.stringWidth(text) > targetWidth && fm.getHeight() > targetHeight);
            return font;
        }

        protected JTextField makeTextField() {
            JTextField text = new JTextField(1);
            text.setBorder(null);
            text.setEditable(false);
            text.setFocusable(false);
            text.setForeground(Color.WHITE);
            text.setOpaque(false);
            text.setFont(textFont);
            text.setHorizontalAlignment(JTextField.CENTER);

            return text;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            Insets insets = getInsets();

            int width = getWidth() - (insets.left + insets.right);
            int height = getHeight() - (insets.top + insets.bottom);

            int xOffset = insets.left;
            int yOffset = insets.top;

            g2d.setColor(Color.WHITE);
            g2d.drawRect(xOffset, yOffset, width, height);

            double colWidth = width / 3d;
            for (int col = 1; col < 3; col++) {
                double xPos = xOffset + (col * colWidth);
                g2d.draw(new Line2D.Double(xPos, yOffset, xPos, yOffset + height));
            }
            double rowHeight = height / 3d;
            for (int row = 1; row < 3; row++) {
                double yPos = xOffset + (row * rowHeight);
                g2d.draw(new Line2D.Double(xOffset, yPos, xOffset + width, yPos));
            }

            g2d.dispose();
        }

    }
}

Now, this is FAR from optimised and you should make some time to see if there are ways to improve it's overall performance. For example componentResized can be called a lot of times within a short period of time, so it might be worth while delaying any updates until it stabilizes.

I would also recommend taking the time learn and understand the layout API, see Laying Out Components Within a Container as a starting point