Reputation: 856
I have JFrame which is having multiple Panels on it. Each Panel is having some Components designed on that. I want to Change the Background Color of Component(JTextField) when it gain Focus. I have Many TextFields and I dont want to Write FocusListener for all the Components. Is there any solution to do it in a Smart Manner.
Upvotes: 2
Views: 4214
Reputation: 347334
You could attach a ProperyChangeListener
to the KeyboardFocusManager @ monitor the appropriate changes
Upvotes: 1
Reputation: 3635
Another way would be to write your own TextFieldUI
which implements the Listener. However, the factory approach is much more elegant.
Example:
import java.awt.Color;
import java.awt.EventQueue;
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.JTextField;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalTextFieldUI;
public class CustomUI extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
UIManager.getDefaults().put("TextFieldUI", CustomTextFieldUI.class.getName());
new CustomUI().setVisible(true);
}
});
}
public CustomUI() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLayout(new FlowLayout());
add(new JTextField(10));
add(new JTextField(10));
pack();
}
public static class CustomTextFieldUI extends MetalTextFieldUI implements FocusListener {
public static ComponentUI createUI(JComponent c) {
return new CustomTextFieldUI();
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
c.addFocusListener(this);
}
public void focusGained(FocusEvent e) {
getComponent().setBackground(Color.YELLOW.brighter());
}
public void focusLost(FocusEvent e) {
getComponent().setBackground(UIManager.getColor("TextField.background"));
}
}
}
Upvotes: 2
Reputation: 51535
You should definitely consider your design, as suggested by @Robin. Creating and configuring all components of an application through a factory helps to make it robust against requirement changes as there is a single location to change instead of being scattered all over the code.
Moreover, an individual listener per component keeps the control near-by to where the focus induced property changes occur, thus not needing state handling in a global listener.
That said, the technical (as in: use with care!) solution for a global focusListener is to register a propertyChangeListener with the KeyboardFocusManager.
A quick code snippet (with very crude state handling :-)
JComponent comp = new JPanel();
for (int i = 0; i < 10; i++) {
comp.add(new JTextField(5));
}
PropertyChangeListener l = new PropertyChangeListener() {
Component owner;
Color background;
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (owner != null && evt.getOldValue() == owner) {
owner.setBackground(background);
owner = null;
}
if (evt.getNewValue() != null) {
owner = (Component) evt.getNewValue();
background = owner.getBackground();
owner.setBackground(Color.YELLOW);
}
}
};
KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("permanentFocusOwner", l);
Upvotes: 10
Reputation: 36621
I dont want to Write FocusListener for all the Components
So you do not want to replace your
JTextField textField = new JTextField();
by
JTextField textField = TextFieldFactory.createTextField();
where TextFieldFactory#createTextField
is a utility method which creates a JTextField
with the desired functionality. Care to elaborate on that ?
Upvotes: 6