I need JTextField to be editable after calling requestFocus() on it's parent container

537 views Asked by At

I have the following window. I need to be able to edit the text when I click on the JTextField.

enter image description here

Explanation: JTextField is inside a JComponent called PriorityPanel. When I click on JTextField, it calls this.requestFocus(); meaning that the PriorityPanel will gain focus. This way I cannot edit the text of the TextField.
In comparison, I can still modify the value of JSlider even if it bahaves exactly the same way. When I click on JSlider, the PriorityPanel will gain focus.

The described problem is in this part:

//constructor
public PriorityPanel(Priority p, int row) {
    this.Slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 100);
    this.model = p;
    this.rowName = row;
    this.TextField = new JTextField(model.getTitle());
    setLayout(new GridLayout(1, 2));     
    add(TextField);
    add(Slider);
    addFocusListener(new FocusAdapter() {
        @Override
        public void focusGained(FocusEvent e) {
            TextField.setBackground(new Color(220, 220, 255));
            Slider.setBackground(new Color(220, 220, 255));
            JPriorityEditor.this.selectedRow = rowName;
        }

        @Override
        public void focusLost(FocusEvent e) {
            TextField.setBackground(Color.WHITE);
            Slider.setBackground(Color.WHITE);
        }
    });
    Slider.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            requestFocus();
        }
    });
    TextField.addMouseListener(new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            requestFocus();
        }
    });
    //atc
}

Here is the SSCCE:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import static test.Priority.staticPriorities;

class Main{
    public static void main(String[] args) {
        staticPriorities.add(new Priority("AutoGen1"));
        staticPriorities.add(new Priority("AutoGen2"));
        GridBagConstraints gbc = new GridBagConstraints();
        JPanel panelAll = new JPanel(new GridBagLayout());
        JPanel panelBottom = new JPanel(new GridLayout(1,2));
        JButton buttonNew = new JButton("buttonNew");
        JButton buttonRemove = new JButton("buttonErase");
        final JPriorityEditor priorityEditor = new JPriorityEditor();

        //Add to panelBottom
        panelBottom.add(buttonNew);
        panelBottom.add(buttonRemove);

        //Add to panelAll
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.fill = GridBagConstraints.BOTH;
        panelAll.add(priorityEditor, gbc);
        gbc.weighty = 0;
        gbc.gridy = 1;
        panelAll.add(panelBottom, gbc);

        buttonNew.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                priorityEditor.AddNewPriority();
            }
        });
        buttonRemove.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                priorityEditor.RemovePriority();
            }
        });

        JFrame d = new JFrame("windowPrioritiesTitle");
        d.add(panelAll, BorderLayout.CENTER);
        d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        d.pack();
        d.setMinimumSize(d.getSize());
        d.setLocationRelativeTo(null);
        d.setVisible(true);
    }
}

/**
 * This is only an object
 * @author Daniel
 */
class Priority {

    public static ArrayList<Priority> staticPriorities = new ArrayList<>();
    private String Title;
    private int Percent;

    public Priority(String title) {
        this.Title = title;
        int sum = 0;
        for (Priority p : staticPriorities) {
            sum += p.Percent;
        }
        this.Percent = 100 - sum;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        this.Title = title;
    }

    public int getPercent() {
        return Percent;
    }

    public void setPercent(int newValue) {
        this.Percent = newValue;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Priority) {
            return ((Priority) obj).getTitle().equals(this.getTitle());
        } else {
            return false;
        }
    }
}

/**
 * My own component
 */
public final class JPriorityEditor extends JScrollPane {

    private PriorityPanel[] priorityPanels;
    private int selectedRow;
    private JPanel con;

    public JPriorityEditor() {
        super(new JPanel());
        this.selectedRow = -1;
        ArrayList<Priority> Priorities = Priority.staticPriorities;
        priorityPanels = new PriorityPanel[Priorities.size()];
        this.con = (JPanel) getViewport().getView();
        con.setLayout(new GridBagLayout());
        con.setBackground(Color.WHITE);
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        int i = 0;
        for (; i < Priorities.size(); i++) {
            gbc.gridy = i;
            priorityPanels[i] = new PriorityPanel(Priorities.get(i), i);
            con.add(priorityPanels[i], gbc);
        }
        gbc.weighty = 1;
        gbc.gridy = i;
        con.add(new JComponent(){},gbc);
    }

    public void AddNewPriority(){
        con.removeAll();
        Priority p = new Priority("NewTitle");
        Priority.staticPriorities.add(p);

        ArrayList<Priority> Priorities = Priority.staticPriorities;
        priorityPanels = new PriorityPanel[Priorities.size()];
        con.setLayout(new GridBagLayout());
        con.setBackground(Color.WHITE);
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        int i = 0;
        for (; i < Priorities.size(); i++) {
            gbc.gridy = i;
            priorityPanels[i] = new PriorityPanel(Priorities.get(i), i);
            con.add(priorityPanels[i], gbc);
        }
        gbc.weighty = 1;
        gbc.gridy = i;
        con.add(new JComponent() {
        }, gbc);
        con.updateUI();
    }

    public void RemovePriority() {
        if (selectedRow != -1) {
            Priority.staticPriorities.remove(Priority.staticPriorities.get(selectedRow));
            con.removeAll();
            ArrayList<Priority> Priorities = Priority.staticPriorities;
            priorityPanels = new PriorityPanel[Priorities.size()];
            con.setLayout(new GridBagLayout());
            con.setBackground(Color.WHITE);
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            int i = 0;
            for (; i < Priorities.size(); i++) {
                gbc.gridy = i;
                priorityPanels[i] = new PriorityPanel(Priorities.get(i), i);
                con.add(priorityPanels[i], gbc);
            }
            gbc.weighty = 1;
            gbc.gridy = i;
            con.add(new JComponent() {
            }, gbc);
            con.updateUI();
        }
    }

    /**
     * Another custom component
     */
    private class PriorityPanel extends JComponent {

        int rowName;
        JSlider Slider;
        JTextField TextField;
        Priority model;

        public PriorityPanel(Priority p, int row) {
            this.Slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 100);
            this.model = p;
            this.rowName = row;
            this.TextField = new JTextField(model.getTitle());
            setLayout(new GridLayout(1, 2));     
            add(TextField);
            add(Slider);
            addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent e) {
                    TextField.setBackground(new Color(220, 220, 255));
                    Slider.setBackground(new Color(220, 220, 255));
                    JPriorityEditor.this.selectedRow = rowName;
                }

                @Override
                public void focusLost(FocusEvent e) {
                    TextField.setBackground(Color.WHITE);
                    Slider.setBackground(Color.WHITE);
                }
            });
            Slider.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    requestFocus();
                }
            });
            TextField.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    requestFocus();
                }
            });
            Slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    int value = Slider.getValue();
                    model.setPercent(value);
                }
            });
            TextField.getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent e) {
                    SetText();
                }

                @Override
                public void removeUpdate(DocumentEvent e) {
                    SetText();
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                    SetText();
                }

                private void SetText() {
                    model.setTitle(TextField.getText());
                }
            });
        }
    }
}
1

There are 1 answers

1
MadProgrammer On BEST ANSWER

From the looks of things, you are trying to modify the state of the parent container when one of the child components becomes focused.

Instead of trying to add a focus listener to the parent container, which is going to cause you some considerable havoc, try adding a single FocusListener to all the child components, for example...

FocusAdapter fa = new FocusAdapter() {
    @Override
    public void focusGained(FocusEvent e) {
        TextField.setBackground(new Color(220, 220, 255));
        Slider.setBackground(new Color(220, 220, 255));
        JPriorityEditor.this.selectedRow = rowName;
    }

    @Override
    public void focusLost(FocusEvent e) {
        TextField.setBackground(Color.WHITE);
        Slider.setBackground(Color.WHITE);
    }
});
Slider.addFocusListener(fa);
TextField.addFocusListener(fa);

Now, I would be taking a peek at the KeyBoardFocusManager#getFocusOwner and back tracking it's container hierarcy when ever focusLost is called to try and determine if the component who now has focus is a child of mine...