带有输入提示的Java JTextField
我想在javax.swing.JTextField中添加一个提示值。它应该看起来像Firefox对带有输入提示的Java JTextField,java,swing,input,jtextfield,hint,Java,Swing,Input,Jtextfield,Hint,我想在javax.swing.JTextField中添加一个提示值。它应该看起来像Firefox对的渲染。这将创建一个文本为“bla”的编辑字段。如果文本框具有焦点,则标题文本将消失,如果用户离开编辑框而没有文本,则标题文本将重新出现 有这样的(自由)swing组件吗?对于任何swing组件(即任何扩展JComponent的组件),您都可以调用setToolTipText(String)方法 有关更多信息,请参考以下链接: 看看这个: 顺便说一句,您自己实现它并不困难。几个侦听器和自定义渲
的渲染。这将创建一个文本为“bla”的编辑字段。如果文本框具有焦点,则标题文本将消失,如果用户离开编辑框而没有文本,则标题文本将重新出现
有这样的(自由)swing组件吗?对于任何swing组件(即任何扩展JComponent的组件),您都可以调用setToolTipText(String)方法
有关更多信息,请参考以下链接:
顺便说一句,您自己实现它并不困难。几个侦听器和自定义渲染器以及瞧。您可以创建自己的:
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
以下是一个单类复制/粘贴解决方案:
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));
请注意,它发生在
受保护的虚空油漆安全(图形g)
中,如果您仍在寻找解决方案,这里有一个结合了其他答案(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");
以下是一种在任何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;
}
看看网页,感受一下
这可以通过使用焦点侦听器来更新文本字段内容来实现 使类实现焦点侦听器接口:
class YourClass实现了FocusListener
添加一个方法,以便在获得焦点时捕捉空白字段:
public void focus获得(FocusEvent e){
if(JTextField1.getText().equals(“用户名”)){
JTextField1.setText(“”);
}
}
添加一个方法,以便在焦点丢失时捕获,以便在字段为空时重新显示默认条目:
public void focusLost(FocusEvent e){
if(JTextField1.getText().equals(“”){
JTextField1.setText(“用户名”);
//应防止在此状态下处理表单
//因为它将字面上包含用户名的“Username”
}
}
将类注册为文本字段的焦点侦听器:
textField.addFocusListener(this);
在Java教程中了解更多信息。这里是一个基于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"));
}
}
import java.awt.*;
导入java.util.stream.*;
导入javax.swing.*;
/**
*@作者Davethesdane,根据Adam Gawne Cain的建议
*/
公共最终类JTextFieldPromptExample扩展了JFrame{
私有静态JTextField newPromptedJTextField(最终字符串文本,最终字符串提示){
最后一个字符串promptPossiblyNullButNeverWhitespace=prompt==null | | prompt.trim().isEmpty()?null:prompt;
返回新的JTextField(文本){
@凌驾
公共虚空绘制组件(最终图形使用_g2d_){
最终图形2d g2d=(图形2d)改用_g2d_;
超级油漆组件(g2d);
//系统输出打印项次(“油漆:”+g2d);
if(getText().isEmpty())
&&promptPossiblyNullButNeverWhitespace!=null){
g2d.setRenderingHint(renderingHits.KEY\u TEXT\u ANTIALIAS,renderingHits.VALUE\u TEXT\u ANTIALIAS\u ON);
最终插入ins=getInsets();
final FontMetrics fm=g2d.getFontMetrics();
final int cB=getBackground().getRGB();
final int cF=get前台().getRGB();
最终整数m=0xfefe;
最终整数c2=((cB&m)>>>1)+((cF&m)>>>1);/“对于(A,R,G,B)中的X,{Xnew=(Xb+Xf)/2}”
/*
*提示文本颜色应介于前景色和背景色之间,以便始终柔和可见。
*变量c0、c1、m、c2在不溢出8位的情况下同时计算中间色的ARGB字段。
*Swing在调用“paint”方法之前,将图形的字体设置为与JTextField的字体属性相匹配,
*因此提示字体将与JTextField的字体匹配。
*不要认为有任何副作用,因为Swing会在绘制后丢弃图形。
*亚当·加恩·凯恩,2019年8月6日15:55
*/
g2d.setColor(新颜色(c2,真));
g2d.drawString(promptPossiblyNullButNeverWhitespace,ins.left,getHeight()-fm.getDescent()-ins.bottom);
/*
*基于下降和底部插入的y坐标似乎与文本点对齐。
*达维瑟丹,2020年4月10日
*/
}
}
};
}
私有静态最终GridBagConstraints GBC_LEFT=新GridBagConstraints();
私有静态最终GridBagConstraints GBC_RIGHT=新GridBagConstraints();
/**/静止的{
GBC_LEFT.anchor=GridBagConstraints.LINE_START;
GBC_LEFT.fill=GridBagConstraints.HORIZONTAL;
GBC_左。插图=新插图(8,8,0,0);
GBC_RIGHT.gridwidth=GridBagConstraints.rements;
GBC_RIGHT.fill=GridBagConstraints.HORIZONTAL;
GBC_RIGHT.insets=新的插图(8,8,0,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"));
}
}