使用图像和提示装饰JTextField

我正在尝试用图像和提示创建一些看起来更漂亮的JTextFields。 为此,我做了一个覆盖paintComponent方法的装饰器。 我使用装饰器的原因是我想将它应用于其他类型的JTextField,例如JPasswordField。

这是我到目前为止所做的;

在此处输入图像描述

左边的表格中看到的问题是,即使我使用了JPasswordField,paintComponent也似乎忽略了我所假设的密码paintComponent,它可能是密码屏蔽符号。

所以问题是,如何避免重复JTextFields和JPasswordFields的代码,但仍然具有不同的function,如密码屏蔽。

这是装饰器代码;

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,但我无法看到如何在不重复代码的情况下解决这个问题。

文本提示符适用于JPasswordField。

一个区别是输入文本时显示的图标消失。 如果你想让图标永久化,那么我建议你创建一个自定义的“IconBorder *类来绘制一个Icon,而不是在paintComponent()方法中进行自定义绘制。

除非您复制JTextField和JPasswordField的代码,否则您的方法将无法工作。

编辑:

实际上,您不需要创建自定义IconBorder。 MatteBorder支持在边框中绘制图标。

要在文本字段内绘制图标,您需要添加一些插入。 您不希望在组件中硬编码插件,只是为图标添加一点空间,让客户端和子类自己设置。

在此处输入图像描述

在上图中,我用绿色绘制原始插图,用红色绘制其他插图。 首先要扩展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); } } 

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