带有输入提示的 Java JTextField
Posted
技术标签:
【中文标题】带有输入提示的 Java JTextField【英文标题】:Java JTextField with input hint 【发布时间】:2010-12-16 20:58:54 【问题描述】:我想为我的 javax.swing.JTextField
添加一个提示值。它应该看起来像 Firefox 渲染的 <input type="text" title="bla">
。这将在背景中创建一个带有文本“bla”的编辑字段。如果文本框具有焦点,则标题文本会消失,如果用户离开编辑框而没有文本,则会重新出现。
是否有(免费)摆动组件可以做这样的事情?
【问题讨论】:
我在swingx.dev.java.net/issues/show_bug.cgi?id=306发现了一个关于这个的swing错误报告谢谢你的帮助。 2018年并没有单线解决方案。smh 我编写了自己的组件。见这里:github.com/CollinAlpert/APIs/blob/master/javax/swing/… 【参考方案1】:您可以创建自己的:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.*;
public class Main
public static void main(String[] args)
final JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
final JTextField textFieldA = new HintTextField("A hint here");
final JTextField textFieldB = new HintTextField("Another hint here");
frame.add(textFieldA, BorderLayout.NORTH);
frame.add(textFieldB, BorderLayout.CENTER);
JButton btnGetText = new JButton("Get text");
btnGetText.addActionListener(new ActionListener()
@Override
public void actionPerformed(ActionEvent e)
String message = String.format("textFieldA='%s', textFieldB='%s'",
textFieldA.getText(), textFieldB.getText());
JOptionPane.showMessageDialog(frame, message);
);
frame.add(btnGetText, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
class HintTextField extends JTextField implements FocusListener
private final String hint;
private boolean showingHint;
public HintTextField(final String hint)
super(hint);
this.hint = hint;
this.showingHint = true;
super.addFocusListener(this);
@Override
public void focusGained(FocusEvent e)
if(this.getText().isEmpty())
super.setText("");
showingHint = false;
@Override
public void focusLost(FocusEvent e)
if(this.getText().isEmpty())
super.setText(hint);
showingHint = true;
@Override
public String getText()
return showingHint ? "" : super.getText();
如果您仍在使用 Java 1.5,请将 this.getText().isEmpty()
替换为 this.getText().length() == 0
。
【讨论】:
这个解决方案也不错。您将不得不重载 getText() 并过滤提示文本。 我宁愿在 getText() 中使用一个标志来指示当前是否显示提示。否则,如果用户碰巧输入了提示文本,getText() 也会返回一个空字符串。 @MichaelJess,是的,你是对的。我编辑了我的示例以包含一个布尔标志。 @BartKiers 你能告诉我HintTextField 中的getText() 方法是如何工作的吗?我不明白返回^^ @Gerret,如果文本字段显示“提示”,则返回空字符串,否则返回文本字段的实际内容(通过super.getText()
)。如果您不确定 ... ? ... : ...
构造,它被称为三元运算符(三元 if):en.wikipedia.org/wiki/%3F:【参考方案2】:
这是一个在任何 L&F 中看起来都不错的简单方法:
public class HintTextField extends JTextField
public HintTextField(String hint)
_hint = hint;
@Override
public void paint(Graphics g)
super.paint(g);
if (getText().length() == 0)
int h = getHeight();
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Insets ins = getInsets();
FontMetrics fm = g.getFontMetrics();
int c0 = getBackground().getRGB();
int c1 = getForeground().getRGB();
int m = 0xfefefefe;
int c2 = ((c0 & m) >>> 1) + ((c1 & m) >>> 1);
g.setColor(new Color(c2, true));
g.drawString(_hint, ins.left, h / 2 + fm.getAscent() / 2 - 2);
private final String _hint;
【讨论】:
我喜欢这个,因为提示功能成为JTextField
的一项功能,而不是外部附加组件(这是我见过的大多数其他解决方案的情况)。但也许你应该多解释一下代码的作用以及它的工作原理。有没有什么副作用 ?什么保证它将以字段使用的字体绘制提示?
太棒了。这应该是选定的答案。在使用 Synthetica LAF 时,我在使用其他解决方案时遇到了很多麻烦。只需执行g.setFont(g.getFont().deriveFont(Font.ITALIC));
即可添加斜体字体
解释:提示文本颜色应该在前景色和背景色之间,所以它总是可以轻轻地看到。变量 c0,c1,m,c2 同时计算中间颜色的 ARGB 字段而不会溢出 8 位。字体度量 ascent 用于将文本垂直居中。 Swing 在调用“paint”方法之前将 Graphics 的字体设置为匹配 JTextField 的字体属性,因此提示字体将匹配 JTextField 的字体。不要认为有任何副作用,因为 Swing 在绘制后丢弃了 Graphics。
我喜欢这个。这是我发现的少数几个没有问题的解决方案之一。我已经在这个问题上单独发布了一个功能齐全的示例。唯一的区别:我发现使用 getHeight() - fm.getDescent() - ins.bottom
的 y 坐标稍微好一些。
@MarcoOttina 请参阅我在 2020 年 4 月 10 日 @ 12:41 发布的以下帖子,这有帮助吗?【参考方案3】:
这是一个单一的类复制/粘贴解决方案:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.JTextComponent;
public class HintTextFieldUI extends BasicTextFieldUI implements FocusListener
private String hint;
private boolean hideOnFocus;
private Color color;
public Color getColor()
return color;
public void setColor(Color color)
this.color = color;
repaint();
private void repaint()
if(getComponent() != null)
getComponent().repaint();
public boolean isHideOnFocus()
return hideOnFocus;
public void setHideOnFocus(boolean hideOnFocus)
this.hideOnFocus = hideOnFocus;
repaint();
public String getHint()
return hint;
public void setHint(String hint)
this.hint = hint;
repaint();
public HintTextFieldUI(String hint)
this(hint,false);
public HintTextFieldUI(String hint, boolean hideOnFocus)
this(hint,hideOnFocus, null);
public HintTextFieldUI(String hint, boolean hideOnFocus, Color color)
this.hint = hint;
this.hideOnFocus = hideOnFocus;
this.color = color;
@Override
protected void paintSafely(Graphics g)
super.paintSafely(g);
JTextComponent comp = getComponent();
if(hint!=null && comp.getText().length() == 0 && (!(hideOnFocus && comp.hasFocus())))
if(color != null)
g.setColor(color);
else
g.setColor(comp.getForeground().brighter().brighter().brighter());
int padding = (comp.getHeight() - comp.getFont().getSize())/2;
g.drawString(hint, 2, comp.getHeight()-padding-1);
@Override
public void focusGained(FocusEvent e)
if(hideOnFocus) repaint();
@Override
public void focusLost(FocusEvent e)
if(hideOnFocus) repaint();
@Override
protected void installListeners()
super.installListeners();
getComponent().addFocusListener(this);
@Override
protected void uninstallListeners()
super.uninstallListeners();
getComponent().removeFocusListener(this);
像这样使用它:
TextField field = new JTextField();
field.setUI(new HintTextFieldUI("Search", true));
请注意,它发生在protected void paintSafely(Graphics g)
。
【讨论】:
如何使提示变为斜体但用户输入的文本不是? 在paintSafely()
中,您必须根据getText().isEmpty()
是否调用setFont(fontHint)
或setFont(fontOriginal)
,其中fontHint
将派生自构造函数中的原始getFont()
。我还必须覆盖 setFont()
以重新生成它:fontOriginal = getFont(); hintFont = new Font(fontOriginal.getName(), fontOriginal.getStyle() | Font.ITALIC, fontOriginal.getSize());
请注意,我没有使用 font.deriveFont()
,因为它似乎占用了大量内存并且永远不会归还它......
我做了一点修改,效果很好。谢谢。【参考方案4】:
看看这个:http://code.google.com/p/xswingx/
顺便说一句,自己实现它并不是很困难。几个监听器和自定义渲染器,瞧。
【讨论】:
仅供参考,SwingX 组件在使用自定义 LAF 时总是失败。 @adam-gawne-cain 下面的解决方案要好得多。 XSwingX 现在好像不能下载了。【参考方案5】:对于任何 Swing 组件(即任何扩展 JComponent),您都可以调用 setToolTipText(String) 方法。
更多信息,请参考以下链接:
API Documentation for setToolTipText "How to Use Tool Tips" tutorial【讨论】:
我认为他不是在谈论工具提示,他想要像“在此处输入以搜索”这样的灰色文本,当一个人开始输入时它会消失 嗯,你可能是对的,但这符合他提供的 html。 OP .. 如果您希望在输入聚焦/模糊时清除/设置默认文本,请查看 FocusListener:java.sun.com/docs/books/tutorial/uiswing/events/…【参考方案6】:看看https://github.com/mgarin/weblaf/的WebLookAndFeel
WebTextField txtName = new com.alee.laf.text.WebTextField();
txtName.setHideInputPromptOnFocus(false);
txtName.setInputPrompt("Name");
txtName.setInputPromptFont(new java.awt.Font("Ubuntu", 0, 18));
txtName.setInputPromptForeground(new java.awt.Color(102, 102, 102));
txtName.setInputPromptPosition(0);
【讨论】:
【参考方案7】:如果您仍在寻找解决方案,以下是结合其他答案(Bart Kiers 和 culmat)的解决方案供您参考:
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
public class HintTextField extends JTextField implements FocusListener
private String hint;
public HintTextField ()
this("");
public HintTextField(final String hint)
setHint(hint);
super.addFocusListener(this);
public void setHint(String hint)
this.hint = hint;
setUI(new HintTextFieldUI(hint, true));
//setText(this.hint);
public void focusGained(FocusEvent e)
if(this.getText().length() == 0)
super.setText("");
public void focusLost(FocusEvent e)
if(this.getText().length() == 0)
setHint(hint);
public String getText()
String typed = super.getText();
return typed.equals(hint)?"":typed;
class HintTextFieldUI extends javax.swing.plaf.basic.BasicTextFieldUI implements FocusListener
private String hint;
private boolean hideOnFocus;
private Color color;
public Color getColor()
return color;
public void setColor(Color color)
this.color = color;
repaint();
private void repaint()
if(getComponent() != null)
getComponent().repaint();
public boolean isHideOnFocus()
return hideOnFocus;
public void setHideOnFocus(boolean hideOnFocus)
this.hideOnFocus = hideOnFocus;
repaint();
public String getHint()
return hint;
public void setHint(String hint)
this.hint = hint;
repaint();
public HintTextFieldUI(String hint)
this(hint, false);
public HintTextFieldUI(String hint, boolean hideOnFocus)
this(hint, hideOnFocus, null);
public HintTextFieldUI(String hint, boolean hideOnFocus, Color color)
this.hint = hint;
this.hideOnFocus = hideOnFocus;
this.color = color;
protected void paintSafely(Graphics g)
super.paintSafely(g);
JTextComponent comp = getComponent();
if(hint != null && comp.getText().length() == 0 && (!(hideOnFocus && comp.hasFocus())))
if(color != null)
g.setColor(color);
else
g.setColor(Color.gray);
int padding = (comp.getHeight() - comp.getFont().getSize()) / 2;
g.drawString(hint, 5, comp.getHeight() - padding - 1);
public void focusGained(FocusEvent e)
if(hideOnFocus) repaint();
public void focusLost(FocusEvent e)
if(hideOnFocus) repaint();
protected void installListeners()
super.installListeners();
getComponent().addFocusListener(this);
protected void uninstallListeners()
super.uninstallListeners();
getComponent().removeFocusListener(this);
Usage:
HintTextField field = new HintTextField();
field.setHint("Here's a hint");
【讨论】:
很好,但是请将“单个代码行”和括号压缩在一行中,以使其更短且更易于阅读(并且不要在新行上打开括号:这有助于弄清楚范围不寻找括号,而只是阅读文本。颜色将有助于发现函数/范围的开始位置)。【参考方案8】:这可以通过使用焦点侦听器来更新文本字段内容来实现。
让类实现焦点监听接口:
class YourClass implements FocusListener
添加一个方法来捕获获得焦点时使字段空白的方法:
public void focusGained(FocusEvent e)
if(JTextField1.getText().equals("Username"))
JTextField1.setText("");
添加一个方法来捕获焦点丢失时重新显示默认条目,如果该字段为空白:
public void focusLost(FocusEvent e)
if(JTextField1.getText().equals(""))
JTextField1.setText("Username");
// you should prevent the form from being processed in this state
// as it will literally contain "Username" for the username
将您的班级注册为文本字段的焦点侦听器:
textField.addFocusListener(this);
在 Java 教程中的 How to Write a Focus Listener 了解更多信息。
【讨论】:
首先,欢迎来到 ***。根据社区的建议,建议在您的源代码中包含上下文,以便更好地阐明您的回复。请查看文档on how to write a good question【参考方案9】:这是一个基于 Adam Gawne-Cain 早期发帖的完整示例。他的解决方案很简单,实际上效果非常好。
我在多个字段的网格中使用了以下文本:
H__|__WWW__+__XXXX__+__WWW__|__H
这样可以轻松验证提示文本的 x/y 对齐方式。
几个观察: - 有许多解决方案,但许多只是表面上起作用和/或有问题 - sun.tools.jconsole.ThreadTab.PromptingTextField 是一个简单的解决方案,但它只在字段没有焦点且它是私有的时显示提示文本,但没有什么是剪切和粘贴无法解决的。
以下适用于 JDK 8 及更高版本:
import java.awt.*;
import java.util.stream.*;
import javax.swing.*;
/**
* @author DaveTheDane, based on a suggestion from Adam Gawne-Cain
*/
public final class JTextFieldPromptExample extends JFrame
private static JTextField newPromptedJTextField (final String text, final String prompt)
final String promptPossiblyNullButNeverWhitespace = prompt == null || prompt.trim().isEmpty() ? null : prompt;
return new JTextField(text)
@Override
public void paintComponent(final Graphics USE_g2d_INSTEAD)
final Graphics2D g2d = (Graphics2D) USE_g2d_INSTEAD;
super.paintComponent(g2d);
// System.out.println("Paint.: " + g2d);
if (getText().isEmpty()
&& promptPossiblyNullButNeverWhitespace != null)
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
final Insets ins = getInsets();
final FontMetrics fm = g2d.getFontMetrics();
final int cB = getBackground().getRGB();
final int cF = getForeground().getRGB();
final int m = 0xfefefefe;
final int c2 = ((cB & m) >>> 1) + ((cF & m) >>> 1); // "for X in (A, R, G, B) Xnew = (Xb + Xf) / 2"
/*
* The hint text color should be halfway between the foreground and background colors so it is always gently visible.
* The variables c0,c1,m,c2 calculate the halfway color's ARGB fields simultaneously without overflowing 8 bits.
* Swing sets the Graphics' font to match the JTextField's font property before calling the "paint" method,
* so the hint font will match the JTextField's font.
* Don't think there are any side effects because Swing discards the Graphics after painting.
* Adam Gawne-Cain, Aug 6 2019 at 15:55
*/
g2d.setColor(new Color(c2, true));
g2d.drawString(promptPossiblyNullButNeverWhitespace, ins.left, getHeight() - fm.getDescent() - ins.bottom);
/*
* y Coordinate based on Descent & Bottom-inset seems to align Text spot-on.
* DaveTheDane, Apr 10 2020
*/
;
private static final GridBagConstraints GBC_LEFT = new GridBagConstraints();
private static final GridBagConstraints GBC_RIGHT = new GridBagConstraints();
/**/ static
GBC_LEFT .anchor = GridBagConstraints.LINE_START;
GBC_LEFT .fill = GridBagConstraints.HORIZONTAL;
GBC_LEFT .insets = new Insets(8, 8, 0, 0);
GBC_RIGHT.gridwidth = GridBagConstraints.REMAINDER;
GBC_RIGHT.fill = GridBagConstraints.HORIZONTAL;
GBC_RIGHT.insets = new Insets(8, 8, 0, 8);
private <C extends Component> C addLeft (final C component)
this .add (component);
this.gbl.setConstraints(component, GBC_LEFT);
return component;
private <C extends Component> C addRight(final C component)
this .add (component);
this.gbl.setConstraints(component, GBC_RIGHT);
return component;
private static final String ALIGN = "H__|__WWW__+__XXXX__+__WWW__|__H";
private final GridBagLayout gbl = new GridBagLayout();
public JTextFieldPromptExample(final String title)
super(title);
this.setLayout(gbl);
final java.util.List<JTextField> texts = Stream.of(
addLeft (newPromptedJTextField(ALIGN + ' ' + "Top-Left" , ALIGN)),
addRight(newPromptedJTextField(ALIGN + ' ' + "Top-Right" , ALIGN)),
addLeft (newPromptedJTextField(ALIGN + ' ' + "Middle-Left" , ALIGN)),
addRight(newPromptedJTextField( null , ALIGN)),
addLeft (new JTextField("x" )),
addRight(newPromptedJTextField("x", "" )),
addLeft (new JTextField(null )),
addRight(newPromptedJTextField(null, null)),
addLeft (newPromptedJTextField(ALIGN + ' ' + "Bottom-Left" , ALIGN)),
addRight(newPromptedJTextField(ALIGN + ' ' + "Bottom-Right", ALIGN)) ).collect(Collectors.toList());
final JButton button = addRight(new JButton("Get texts"));
/**/ addRight(Box.createVerticalStrut(0)); // 1 last time forces bottom inset
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(740, 260));
this.pack();
this.setResizable(false);
this.setVisible(true);
button.addActionListener(e ->
texts.forEach(text -> System.out.println("Text..: " + text.getText()));
);
public static void main(final String[] args)
SwingUtilities.invokeLater(() -> new JTextFieldPromptExample("JTextField with Prompt"));
【讨论】:
以上是关于带有输入提示的 Java JTextField的主要内容,如果未能解决你的问题,请参考以下文章
设置警告框为带有一个密文输入框的样式,并设置输入框键盘为数字键盘;判断密文输入框里的内容,并弹出相应提示