Dynamically define text to Jlabels according to text field validation

Asked

Viewed 673 times

0

I tried to add one label for each required 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 have it "set" the corresponding messages of each label (with the names of each field) not working properly.

In the example I used only 3 fields of the type JTextField, however, the idea is that the amount of fields may 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();
    }
}
  • How many fields did you intend to do this with? If it’s only 3, it’s simple. That’s why it’s important to provide the full context in mcve.

  • @Articuno I was trying to do in a way that was not fixed, could vary .

  • Tip: edit the question and add all the information already spoken here, because in it you say nothing that the method is not fixed to only 3 elements

  • @Articuno added another description

  • May I suggest an alternative of mine on how to do this? I find your code very messy and full of unnecessary and/or redundant things. I just can’t even apply my idea to him.

  • @Articuno can yes, all help is welcome - welcome

  • You really need to use recursion?

  • @Articuno makes your example, I try to adapt as needed, you providing me the base, will already be of great help !

  • A doubt because it is adding empty label Jlabel when it is not a text field?

  • @Articuno I was not going to put to radiobutton, but I think I took the code there, not to pollute more.

Show 5 more comments

1 answer

2


As asked in the comments, this response is an alternative to what you have 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:

  • created field lists(fields) and another for their respective fields, and added these according to the amount of fields;

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

  • when adding a label referring to the notice to fill in a text field, a preincrement in linhaAtual so that this component is added to the line below the text field;

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

  • the method validaComponentes() is leaner thanks to our lists of text fields and Abels, without the need for recursiveness to sweep the fields. With an additional, it now also cleans the Abels when the field passes the validation.

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

Using InputVerifier I think you’ll be more friendly, if you want an example, see at this link or in this answer what I did here on the site.

  • Just a doubt, in case to add components that are not mandatory, it will return me an Indexoutofboundsexception, since the amount of components will be greater than that of Abels, even if I put to set only in the mandatory fields. For example, change field 02 to not mandatory.

  • @Gustavosantos just add only required fields to the list, since if a field is not required, it does not need a label to validate it.

  • is already done like this, it just adds to the required ones, and to validate I even added one more condition "if (Fields.get(i). isEmpty() && Fields.get(i). eObrigatorio()) "

  • @Gustavosantos If only required fields are added to the list, there is no way to pop indexoffbound. Check there, you must be adding non-mandatory fields together.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.