2011-05-22 54 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()); 
    } 
}