使用图像和提示装饰 JTextField
我正在尝试使用图像和提示创建一些看起来更漂亮的 JTextFields。为此,我创建了一个重写 PaintComponent 方法的装饰器。我使用装饰器的原因是我想将其应用于其他类型的 JTextField,例如 JPasswordField。
这是我到目前为止所做的;
左侧表单中看到的问题是,即使我使用了 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,但我不知道如何在不重复代码的情况下解决这个问题。
I'm trying to create some nicer looking JTextFields with an image and a hint. To do this I made a decorator that overrides the paintComponent method. The reason I used a decorator is that I wanted to apply it to other types of JTextField such as JPasswordField.
Here is what I've made so far;
The problem as seen in the form on the left is that, even though I have used a JPasswordField the paintComponent seems to ignore what I assume is the passwords paintComponent which presumably does the password masking symbols.
So the question is, how can I avoid duplicating the code for JTextFields and JPasswordFields but still have the different functionality such as password masking.
This is the decorator code;
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();
}
}
And this is where I create the fields;
JTextField usernameField = new JTextFieldHint(new JTextField(),"user_green","Username");
JTextField passwordField = new JTextFieldHint(new JPasswordField(),"bullet_key","Password");
Hopefully i've not went completely off in the wrong direction here!
Thanks!
EDIT : Again the more I look at it, it is obvious that calling super.paintComponent(g) is going to call the JTextFields paintcomponent, but I can't see how to solve this without duplicating the code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
文本提示与 JPasswordField 配合使用。
一个区别是,输入文本时显示的图标会消失。如果您希望图标是永久的,那么我建议您创建一个自定义的“IconBorder* 类来绘制图标,而不是在 PaintComponent() 方法中进行自定义绘制。
除非您复制 JTextField 和 JPasswordField 的代码,否则您的方法将不起作用 实际上
编辑:
您不需要创建自定义 IconBorder。MatteBorder 支持在边框中绘制图标。
Text Prompt works with a JPasswordField.
One difference is that the displayed icon disappears when text is entered. If you want the icon to be permanent then I suggest you create a custom "IconBorder* class to paint an Icon rather then do custom painting in the paintComponent() method.
You approach will not work unless you duplicate the code for both JTextField and JPasswordField.
Edit:
Actually you don't need to create a custom IconBorder. The MatteBorder supports the painting of an Icon in a Border.
为了在文本字段内绘制图标,您需要添加一些插图。
您不想在组件中对插入进行硬编码,而只需为图标添加一点空间,让客户端和子类设置自己的图标。
在上图中,我将原始插图绘制为绿色,将附加插图绘制为红色。首先您要扩展 JTextField。我们跟踪两件事:原始插图(绿色的)
mBorder
和图标。然后你需要重写
setBorder()
方法。在这里,如果我们有一个图标(字段
mIcon
不是null
),我们使用复合边框添加额外的插图。然后,您还应该覆盖paintComponent()
方法。最后,您需要一个
setIcon()
方法。我们在这里所做的是保存图标并重新计算边框。
如果您想对 JPasswordField 执行相同的操作,最优雅的方法可能是使用上面讨论的所有方法创建一个辅助类。
并像这样使用它:
In order to paint an icon inside a text field you need to add some insets.
You don't want to hard-code insets in your component but just add a little bit of space for the icon, letting clients and subclasses to set their own.
In the figure above I painted original insets in green and additional insets in red. First thing you want to extend JTextField. We keep track of two things: the original insets (the green ones)
mBorder
, and the icon.Then you need to override
setBorder()
method.Here, if we have an icon (the field
mIcon
is notnull
), we add our additional insets using a compound border. Then, you should also override thepaintComponent()
method.Finally, you need a
setIcon()
method.What we are doing here is saving the icon and recalculating the borders.
If you want to do the same same thing with
JPasswordField
, the most elegant thing is probably to create a helper class with all the methods discussed above.And use it like this: