2011-05-22 39 views
9

我想用图像和提示创建一些更好看的JTextFields。为此,我制作了一个覆盖paintComponent方法的装饰器。我使用装饰器的原因是我想将它应用于其他类型的JTextField,如JPasswordField。用图像和提示装饰JTextField

这是我到目前为止;

enter image description here

如被看见在左边的表格的问题是,即使我已经使用了一个JPasswordField中的的paintComponent似乎忽略了我认为是密码的paintComponent这大概确实的密码屏蔽符号。

所以问题是,我如何避免重复JTextFields和JPasswordFields的代码,但仍然具有不同的功能,如密码掩码。

这是装饰者代码;

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(); 
} 


} 

而这是我创造的领域;

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

希望我没有完全在这里错误的方向去!

谢谢!

编辑:再次看到它,很明显,调用super.paintComponent(g)将要调用JTextFields paintcomponent,但我无法看到如何解决这个问题,而无需重复代码。

回答

8

Text Prompt使用JPasswordField。

一个不同之处在于输入文本时显示的图标消失。如果你想让这个图标成为永久图标,我建议你创建一个自定义的“IconBorder *”类来绘制图标,而不是在paintComponent()方法中进行自定义绘画。两者的JTextField和JPasswordField中

编辑:

其实你并不需要创建一个自定义的IconBorder的MatteBorder支持图标的绘画在边境

+0

你是说Border Border = BorderFactory ....只是+1 – mKorbel 2011-05-22 21:44:19

+0

你可以创建一个CompoundBorder。使用原始边框作为外部边框,然后使用带有图标的MatteBorder作为内部边框 – camickr 2011-05-22 22:07:32

+0

清晰直接,谢谢 – mKorbel 2011-05-22 23:03:52

3

为了画里面的图标。一个文本字段,你需要添加一些插页。 你不想组件中的硬编码插入,但只需为图标添加一点空间,让客户端和子类设置它们自己的空间。

enter image description here

在上图中,我画在绿色的和额外的插图原插图为红色。首先你要扩展JTextField。我们跟踪两件事:原始插图(绿色插图)mBorder和图标。

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

    // ... 
} 

然后你需要重写setBorder()方法。

@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); 
    } 
} 

在这里,如果我们有一个图标(场mIconnull),我们添加我们使用复合边框额外的插图。然后,您还应该覆盖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); 
    } 
} 

最后,您需要一个setIcon()方法。

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

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

我们在这里做的是保存图标和重新计算的边界。

如果你想用JPasswordField做同样的事情,最优雅的事情可能是用上面讨论的所有方法创建一个辅助类。

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); 
    } 
} 

并且像这样使用它。

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()); 
    } 
}