Define text to JLabels dynamically according to validation of text fields

0

I tried to add a label to each mandatory component of my screen that is empty (field 01 and field 02), so I created a list of labels with the corresponding amount of fields / components. However, the attempts I made to "set" the corresponding messages of each label (with the names of each field) do not work properly.

In the example I used only 3 fields of type JTextField , but the idea is that the number of fields can vary.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class AdicionaCmp extends JFrame {

    private MeuJTextField jTextField1 = new MeuJTextField(true, "Campo 01");
    private MeuJTextField jTextField2 = new MeuJTextField(true, "Campo 02");
    private MeuJTextField jTextField3 = new MeuJTextField(false, "Campo 03");
    private JButton jButton = new JButton("Validar");
    //private JLabel labelInferior = new JLabel();
    private Font fonte = new Font("Arial", Font.PLAIN, 10);

    private List<JLabel> listLabel = new ArrayList<>();
    private List<JComponent> listComponentes = new ArrayList<>();

    public static void main(String[] args) {
        EventQueue.invokeLater(AdicionaCmp::new);
    }

    public AdicionaCmp() {
        add(montaTela());
        //setSize(600, 350);
        pack();

        setVisible(true);
        actionButton();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private JComponent montaTela() {
        JPanel painelPrincipal = new JPanel();

        JPanel painel = new JPanel();
        painel.setLayout(new GridBagLayout());
        adicionaComponente(1, 1, 1, 1, painel, painelPrincipal);
        adicionaComponente(1, 1, 1, 2, jTextField1, painel);
        adicionaComponente(2, 1, 1, 2, jTextField2, painel);
        adicionaComponente(3, 1, 1, 2, jTextField3, painel);
        adicionaComponente(4, 1, 1, 1, jButton, painel);
        return painelPrincipal;
    }

    public void adicionaComponente(int linha, int coluna, int linhas, int colunas, JComponent componente, JPanel painel) {

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridy = linha;
        gbc.gridx = coluna;
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(5, 5, 5, 5);

        JPanel painelInterno = new JPanel();
        painelInterno.setLayout(new GridBagLayout());
        JLabel rotulo = new JLabel();

        if (componente instanceof MeuJTextField) {
            rotulo = new JLabel(((MeuJTextField) componente).getNome());
        }

        GridBagConstraints gbc1 = new GridBagConstraints();
        gbc1.gridx = 1;
        gbc1.gridy = 1;
        gbc1.anchor = GridBagConstraints.WEST;
        gbc1.insets = new Insets(5, 5, 5, 5);
        painelInterno.add(rotulo, gbc1);

        GridBagConstraints gbc2 = (GridBagConstraints) gbc1.clone();
        gbc2.gridx = 2;
        gbc2.fill = GridBagConstraints.BOTH;
        gbc2.gridwidth = GridBagConstraints.REMAINDER; //Especifica que esse componente é o último componente em sua coluna ou linha.
        painelInterno.add(componente, gbc2);

        GridBagConstraints gbc3 = (GridBagConstraints) gbc1.clone();
        gbc3.gridx = 2;
        gbc3.gridy = 2;

        listComponentes.add(componente);

        if ((componente instanceof MeuJTextField) && (((MeuJTextField) componente).eObrigatorio())) {

            JLabel labelInferior = new JLabel();

            for (int i = 0; i < listComponentes.size(); i++) {
                labelInferior = new JLabel();
                painelInterno.add(labelInferior, gbc3);
                setMessage(listLabel, ((MeuJTextField) componente).getNome());
                //listLabel.add(labelInferior);
            }
            listLabel.add(labelInferior);
        }

        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridx++;
        gbc.gridheight = linhas;
        gbc.gridwidth = colunas;
        painel.add(painelInterno, gbc);
    }

    private void actionButton() {
        jButton.addActionListener(e -> {
            validaComponentes();
        });
    }

    private void setMessage(List<JLabel> listLabel, String message) {
        for (JLabel labels : listLabel) {
            labels.setFont(fonte);
            labels.setForeground(new Color(255, 21, 8));
            labels.setText(message);
        }
        pack();
    }

    private boolean validaComponentes() {
        java.lang.reflect.Field[] allFields = this.getClass().getDeclaredFields();
        for (java.lang.reflect.Field field : allFields) {
            if (Modifier.isPrivate(field.getModifiers())) {
                try {
                    field.setAccessible(true);
                    Object fieldValue = field.get(this);
                    if (fieldValue instanceof MeuJTextField) {
                        if (((MeuJTextField) fieldValue).isEmpty()) {
                            setMessage(listLabel, "O " + ((MeuJTextField) fieldValue).getNome() + " não pode ser vazio !");
                            return false;
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return true;

    }

    class MeuJTextField extends JTextField implements MeuComponente {

        private boolean eObrigatorio;
        private String nome;

        public MeuJTextField(boolean eObrigatorio, String nome) {
            this.eObrigatorio = eObrigatorio;
            this.nome = nome;
            setPreferredSize(new Dimension(200, 25));
        }

        @Override
        public String getNome() {
            return nome;
        }

        public boolean isEmpty() {
            return getText().trim().isEmpty();
        }

        @Override
        public boolean eObrigatorio() {
            return eObrigatorio;
        }
    }

    public interface MeuComponente {

        public String getNome();

        public boolean eObrigatorio();
    }
}
    
asked by anonymous 04.12.2017 / 20:59

1 answer

2

As asked in the comments, this answer is an alternative to what you've already done, which makes the code more organized and readable:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;


public class ValidarCamposComLabelTest  extends JFrame{

    private List<MeuJTextField> fields =  new ArrayList<>();
    private List<JLabel> labels = new ArrayList<>();
    private JButton jButton = new JButton("Validar");

    private Font fonte = new Font("Arial", Font.PLAIN, 10);

    public static void main(String[] args) {
        EventQueue.invokeLater(ValidarCamposComLabelTest::new);
    }

    public ValidarCamposComLabelTest() {

        JPanel painelPrincipal = new JPanel();

        JPanel painel = new JPanel();
        painel.setLayout(new GridBagLayout());

        fields.add(new MeuJTextField(true, "Campo 01"));
        fields.add(new MeuJTextField(true, "Campo 02"));
        fields.add(new MeuJTextField(true, "Campo 03"));

        int linhaAtual = 1;

        for(int i = 0; i < fields.size(); i++, linhaAtual++) {
            adicionaComponente(linhaAtual, 1, 1, 1, new JLabel(fields.get(i).getNome()), painel);
            adicionaComponente(linhaAtual, 2, 1, 2, fields.get(i), painel);

            if(fields.get(i).eObrigatorio()) {

                JLabel label = new JLabel("");
                label.setFont(fonte);
                label.setForeground(new Color(255, 21, 8));
                adicionaComponente(++linhaAtual, 2, 1, 1, label, painel);
                labels.add(label);
            } 
        }


        adicionaComponente(++linhaAtual, 1, 1, 1, jButton, painel);
        jButton.addActionListener(e -> validaComponentes());

        painelPrincipal.add(painel);
        add(painelPrincipal);
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    private boolean validaComponentes() {
        boolean retorno = true;

        for(int i = 0; i <fields.size(); i++) {
            if(fields.get(i).isEmpty()) {
                labels.get(i).setText(fields.get(i).getNome() +  " não pode ser vazio !");
                retorno = false;
            } else {
                labels.get(i).setText("");
            }
        }
        pack();
        return retorno;
    }

    private void adicionaComponente(int linha, int coluna, int linhas, int colunas, JComponent componente,
            JPanel painel) {

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridy = linha;
        gbc.gridx = coluna;
        gbc.gridheight = linhas;
        gbc.gridwidth = colunas;
        gbc.insets = new Insets(5, 5, 5, 5);        
        painel.add(componente, gbc);

    }

    class MeuJTextField extends JTextField implements MeuComponente {

        private boolean eObrigatorio;
        private String nome;

        public MeuJTextField(boolean eObrigatorio, String nome) {
            this.eObrigatorio = eObrigatorio;
            this.nome = nome;
            setPreferredSize(new Dimension(200, 25));
        }

        @Override
        public String getNome() {
            return nome;
        }

        public boolean isEmpty() {
            return getText().trim().isEmpty();
        }

        @Override
        public boolean eObrigatorio() {
            return eObrigatorio;
        }
    }

    public interface MeuComponente {

        public String getNome();

        public boolean eObrigatorio();
    }
}

Changes I've made:

  • I created field lists ( fields ) and another one for their respective labels, and added them according to the number of fields;

  • variable linhaAtual was created to be able to control the addition of the components added in the variable painel ;

  • When you add a label for the prompt to fill in a text field, a pre-increment in linhaAtual so that this component is added in the line below the text field;

  • The adicionaComponente() method has been abstracted, so it can now be used to add any component to any panel on your screen that has GridBagLayout as its layout, respecting the values passed to GridBagConstraints ;

  • The validaComponentes() method is smoother thanks to our lists of text fields and labels, without the need for recursion to scan the fields. With an add-on, it now also clears the labels when the field passes validation.

I reiterate that although functional, I particularly find this form of validation approach very bad, filling the screen of labels to show message of each field does not improve the UX of your application, quite the contrary.

Using InputVerifier I think you're more friendly, if For an example, see in this link or in this response I did here on the site.

    
05.12.2017 / 14:42