Apply component focus

Asked

Viewed 234 times

0

I have a component that is a JPanel containing two JTextFields, wanted to be able to apply borders and funds only for the JTextFields, without applying on the panel.

I treat everything on the main screen so that it is applied to everything of the type JComponent, and also because the component can be applied to several screens.

For other components such as JTextFields and the JTextArea, it applies correctly.

Simplified example:

package focu;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;

public class TelaPrincipal extends JFrame implements FocusListener {

    private JLabel label = new JLabel("Componente:");
    private MeuComponente comp = new MeuComponente();
    private JLabel label2 = new JLabel("JTextField:");
    JTextField jt = new JTextField();
    private JLabel label3 = new JLabel("JTextArea:");
    JTextArea area = new JTextArea();

    public static void main(String[] args) {
        TelaPrincipal teste = new TelaPrincipal();
        teste.setVisible(true);
    }

    public TelaPrincipal() {
        setTitle("Teste");
        add(montaTela());
        //setSize(150, 300);
        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    private JComponent montaTela() {
        JPanel painel = new JPanel();
        painel.setLayout(new FlowLayout());

        painel.add(label);
        painel.add(comp);
        comp.addFocusListener(this);

        painel.add(label2);
        painel.add(jt);
        jt.setPreferredSize(new Dimension(100, 20));
        jt.addFocusListener(this);

        painel.add(label3);
        painel.add(area);
        area.setPreferredSize(new Dimension(100, 100));
        area.addFocusListener(this);

        return painel;
    }

    @Override
    public void focusGained(FocusEvent fe) {
        if (fe.getSource() instanceof JComponent) {
            ((JComponent) fe.getSource()).setBorder(new LineBorder(Color.RED));
            ((JComponent) fe.getSource()).setBackground(Color.LIGHT_GRAY);
        }
    }

    @Override
    public void focusLost(FocusEvent e) {
        ((JComponent) e.getSource()).setBorder(new LineBorder(Color.GRAY));
        ((JComponent) e.getSource()).setBackground(Color.WHITE);
    }
}

class MeuComponente extends JPanel
{
    public JTextField jt01 = new JTextField();
    public JTextField jt02 = new JTextField();

    public MeuComponente()
    {
        setLayout(new FlowLayout());
        add(jt01);
        jt01.setPreferredSize(new Dimension(70, 20));    
        add(jt02);
        jt02.setPreferredSize(new Dimension(70, 20));
    }
}

1 answer

4


Should not apply FocusListener to top-level components as JFrame. If the goal was to control the focus of the screen, you should use WindowListener.

But as the goal, at least as I understand it, is to change component characteristics, the focus should be applied to each one individually, because the focus is not something shared. To do this, you need to scan all components of the screen and, if these components are containers, also scan the components contained internally.

To make this more automated and flexible to additions of new components on the screen, you can rescue a list of all components by using the method getComponents(), and to facilitate this scan, a good solution is to create a loop-containing method to apply the System to focus on components and use recursiveness, in the case of panels containing other internal panels with more components:

private void setFocusInComponents(Container container) {

    Component[] components = container.getComponents();

    for (Component comp : components) {

        if (comp instanceof Container) {
            setFocusInComponents((Container) comp);
        }

        comp.addFocusListener(new FocusListener() {

            @Override
            public void focusLost(FocusEvent e) {
                // TODO Auto-generated method stub
                JComponent comp = (JComponent) e.getSource();

                comp.setBorder(new LineBorder(Color.GRAY));
                comp.setBackground(Color.WHITE);

            }

            @Override
            public void focusGained(FocusEvent e) {
                // TODO Auto-generated method stub
                JComponent comp = (JComponent) e.getSource();

                comp.setBorder(new LineBorder(Color.RED));
                comp.setBackground(Color.LIGHT_GRAY);

            }
        });
    }
}

To use the method in your code, simply call setFocusInComponents() after adding all components to the JFrame, passing the method getcontentPane() as parameter, since this method returns the panel that holds everything that is added in the JFrame.

setFocusInComponents(this.getContentPane());

It is always good to remember that swing applications should always be started within the specific thread for it.

  • it worked perfectly, just a doubt, whatever that is (Component comp : Components) { } ? I didn’t know you could do it that way. And the method can be used in Jinternalframe as well ?

  • 1

    @Java Is a loop that traverses the list of components returned by the method getComponentes(). As every component is a JComponent, everyone inherits this method. Hence the check if it is a type Container, since we are not interested in going through components of a jtextfield or label, since it is difficult for these components to store others internally.

  • 1

    @Java the method setFocusInComponents() works with any component that is passed to it, JInternalFrame includes in this list.

  • in the actual application, it is not working. The only difference is how I add the components. There I use Gridbaglayout and in the example I used Flow

  • @Java but the method has nothing to do with the layout. Do not forget that it should be invoked after the screen is already practically with all components inserted, otherwise it will not work at all. If you are using Nimbus as a theme, it may not work because the theme already has the focus colors set.

  • So I had put in the constructor, plus, as I have a method that adds the components, removed and put at the end of this method, after they add the components, but it didn’t work.

  • @Java are you applying some custom theme or Nimbus? It is not every theme that accepts this type of modification. In the question code is the most standard theme, it accepts, but other themes may impose themselves and not accept.

  • i am using a Lookandfeel, but it works on it, in my application is the same theme, more n works

Show 4 more comments

Browser other questions tagged

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