2011-05-22 29 views
9

Estoy tratando de crear algunos JTextFields más atractivos con una imagen y una pista. Para hacer esto hice un decorador que anula el método paintComponent. La razón por la que utilicé un decorador es porque quería aplicarlo a otros tipos de JTextField como JPasswordField.Decorar un JTextField con una imagen y sugerencia

Esto es lo que he hecho hasta ahora;

enter image description here

El problema, como se ve en la forma de la izquierda es que, a pesar de que he utilizado una JPasswordField la paintComponent parece ignorar lo que supongo que es el paintComponent contraseñas que presumiblemente hace los símbolos contraseña de enmascaramiento.

Así que la pregunta es, ¿cómo puedo evitar la duplicación del código para JTextFields y JPasswordFields, pero todavía tengo las diferentes funcionalidades como el enmascaramiento de contraseñas.

Este es el código del decorador;

public class JTextFieldHint extends JTextField implements FocusListener{ 
private JTextField jtf; 
private Icon icon; 
private String hint; 
private Insets dummyInsets; 

public JTextFieldHint(JTextField jtf, String icon, String hint){ 
    this.jtf = jtf; 
    setIcon(createImageIcon("icons/"+icon+".png",icon)); 
    this.hint = hint; 

    Border border = UIManager.getBorder("TextField.border"); 
    JTextField dummy = new JTextField(); 
    this.dummyInsets = border.getBorderInsets(dummy); 

    addFocusListener(this); 
} 

public void setIcon(Icon newIcon){ 
    this.icon = newIcon; 
} 

@Override 
protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     int textX = 2; 

     if(this.icon!=null){ 
      int iconWidth = icon.getIconWidth(); 
      int iconHeight = icon.getIconHeight(); 
      int x = dummyInsets.left + 5; 
      textX = x+iconWidth+2; 
      int y = (this.getHeight() - iconHeight)/2; 
      icon.paintIcon(this, g, x, y); 
     } 

     setMargin(new Insets(2, textX, 2, 2)); 

     if (this.getText().equals("")) { 
      int width = this.getWidth(); 
      int height = this.getHeight(); 
      Font prev = g.getFont(); 
      Font italic = prev.deriveFont(Font.ITALIC); 
      Color prevColor = g.getColor(); 
      g.setFont(italic); 
      g.setColor(UIManager.getColor("textInactiveText")); 
      int h = g.getFontMetrics().getHeight(); 
      int textBottom = (height - h)/2 + h - 4; 
      int x = this.getInsets().left; 
      Graphics2D g2d = (Graphics2D) g; 
      RenderingHints hints = g2d.getRenderingHints(); 
      g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
      g2d.drawString(hint, x, textBottom); 
      g2d.setRenderingHints(hints); 
      g.setFont(prev); 
      g.setColor(prevColor); 
     } 

} 

protected ImageIcon createImageIcon(String path, String description) { 
    java.net.URL imgURL = getClass().getResource(path); 
    if (imgURL != null) { 
     return new ImageIcon(imgURL, description); 
    } else { 
     System.err.println("Couldn't find file: " + path); 
     return null; 
    } 
} 

@Override 
public void focusGained(FocusEvent arg0) { 
    this.repaint(); 
} 

@Override 
public void focusLost(FocusEvent arg0) { 
    this.repaint(); 
} 


} 

Y aquí es donde creo los campos;

JTextField usernameField = new JTextFieldHint(new JTextField(),"user_green","Username"); 
JTextField passwordField = new JTextFieldHint(new JPasswordField(),"bullet_key","Password"); 

Espero que no haya salido completamente en la dirección equivocada aquí!

Gracias!

EDITAR: De nuevo, cuanto más lo miro, es obvio que llamar a super.paintComponent (g) va a llamar al componente de pintura JTextFields, pero no veo cómo resolverlo sin duplicar el código.

Respuesta

8

Text Prompt funciona con un JPasswordField.

Una diferencia es que el icono que se muestra desaparece cuando se ingresa el texto. Si desea que el icono sea permanente, le sugiero que cree una clase personalizada "IconBorder" para pintar un ícono en lugar de hacer una pintura personalizada en el método paintComponent().

Su aproximación no funcionará a menos que duplique el código para tanto JTextField y JPasswordField

Editar:.

en realidad no es necesario para crear un IconBorder personalizada el MatteBorder es compatible con la pintura de un icono en una frontera

+0

¿Estáis destinados frontera Border = BorderFactory ...., solo 1 – mKorbel

+0

Puede crear una CompoundBorder. Utilice el borde original como el borde exterior y luego utilice un MatteBorder con un icono como el borde interno – camickr

+0

claro y directo, gracias – mKorbel

3

para pintar un icono dentro.. un campo de texto que necesita agregar algunas inserciones. No desea insertos de código duro en su componente, pero solo agregue un poco de espacio para el icono, permitiendo que los clientes y las subclases establezcan los suyos propios.

enter image description here

En la figura anterior Pinté inserciones originales en recuadros verdes y adicionales en rojo. Lo primero que desea es extender JTextField. Hacemos un seguimiento de dos cosas: las inserciones originales (las verdes) mBorder, y el ícono.

public class IconTextField extends JTextField { 
    private Border mBorder; 
    private Icon mIcon; 

    // ... 
} 

Luego hay que anular setBorder() método.

@Override 
public void setBorder(Border border) { 
    mBorder = border; 

    if (mIcon == null) { 
     super.setBorder(border); 
    } else { 
     Border margin = BorderFactory.createEmptyBorder(0, mIcon.getIconWidth() + ICON_SPACING, 0, 0); 
     Border compoud = BorderFactory.createCompoundBorder(border, margin); 
     super.setBorder(compoud); 
    } 
} 

Aquí, si tenemos un icono (el campo mIcon no es null), añadimos nuestras inserciones adicionales utilizando un borde compuesto. Luego, también debe anular el método paintComponent().

@Override 
protected void paintComponent(Graphics graphics) { 
    super.paintComponent(graphics); 

    if (mIcon != null) { 
     Insets iconInsets = mBorder.getBorderInsets(this); 
     mIcon.paintIcon(this, graphics, iconInsets.left, iconInsets.top); 
    } 
} 

Por último, necesita un método setIcon().

public void setIcon(Icon icon) { 
    mIcon = icon; 
    resetBorder(); 
} 

private void resetBorder() { 
    setBorder(mBorder); 
} 

Lo que hacemos aquí es guardar el icono y volver a calcular los bordes.

Si desea hacer lo mismo con JPasswordField, lo más elegante es probablemente crear una clase de ayuda con todos los métodos mencionados anteriormente.

class IconTextComponentHelper { 
    private static final int ICON_SPACING = 4; 

    private Border mBorder; 
    private Icon mIcon; 
    private Border mOrigBorder; 
    private JTextComponent mTextComponent; 

    IconTextComponentHelper(JTextComponent component) { 
     mTextComponent = component; 
     mOrigBorder = component.getBorder(); 
     mBorder = mOrigBorder; 
    } 

    Border getBorder() { 
     return mBorder; 
    } 

    void onPaintComponent(Graphics g) { 
     if (mIcon != null) { 
      Insets iconInsets = mOrigBorder.getBorderInsets(mTextComponent); 
      mIcon.paintIcon(mTextComponent, g, iconInsets.left, iconInsets.top); 
     } 
    } 

    void onSetBorder(Border border) { 
     mOrigBorder = border; 

     if (mIcon == null) { 
      mBorder = border; 
     } else { 
      Border margin = BorderFactory.createEmptyBorder(0, mIcon.getIconWidth() + ICON_SPACING, 0, 0); 
      mBorder = BorderFactory.createCompoundBorder(border, margin); 
     } 
    } 

    void onSetIcon(Icon icon) { 
     mIcon = icon; 
     resetBorder(); 
    } 

    private void resetBorder() { 
     mTextComponent.setBorder(mOrigBorder); 
    } 
} 

Y úsala así.

public class IconTextField extends JTextField { 
    private IconTextComponentHelper mHelper = new IconTextComponentHelper(this); 

    public IconTextField() { 
     super(); 
    } 

    public IconTextField(int cols) { 
     super(cols); 
    } 

    private IconTextComponentHelper getHelper() { 
     if (mHelper == null) 
      mHelper = new IconTextComponentHelper(this); 

     return mHelper; 
    } 

    @Override 
    protected void paintComponent(Graphics graphics) { 
     super.paintComponent(graphics); 
     getHelper().onPaintComponent(graphics); 
    } 

    public void setIcon(Icon icon) { 
     getHelper().onSetIcon(icon); 
    } 

    public void setIconSpacing(int spacing) { 
     getHelper().onSetIconSpacing(spacing); 
    } 

    @Override 
    public void setBorder(Border border) { 
     getHelper().onSetBorder(border); 
     super.setBorder(getHelper().getBorder()); 
    } 
} 
Cuestiones relacionadas