带有输入提示的 Java JTextField

发布于 2024-08-11 09:23:34 字数 235 浏览 8 评论 0原文

我想向我的 javax.swing.JTextField 添加提示值。它应该看起来像 的 Firefox 渲染。这将创建一个背景为文本“bla”的编辑字段。如果文本框具有焦点,标题文本就会消失,如果用户离开编辑框而没有文本,标题文本就会重新出现。

是否有(免费)摆动组件可以执行类似的操作?

I would like to add a hint value to my javax.swing.JTextField. It should look like Firefox rendering of <input type="text" title="bla">. This creates an edit field with the text 'bla' in the background. If the textbox has focus the title-text disappears and just reappears if the user leaves the editbox without text.

Is there a (free) swing component that does something like this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

请你别敷衍 2024-08-18 09:23:34

您可以创建自己的:

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< /代码>。

You could create your own:

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();
  }
}

If you're still on Java 1.5, replace the this.getText().isEmpty() with this.getText().length() == 0.

尘曦 2024-08-18 09:23:34

这是一个在任何 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;
}

Here is a simple way that looks good in any 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;
}
好菇凉咱不稀罕他 2024-08-18 09:23:34

这是一个单类复制/粘贴解决方案:

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) 中。

Here is a single class copy/paste solution:

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);
    }
}

Use it like this:

TextField field = new JTextField();
field.setUI(new HintTextFieldUI("Search", true));

Note that it is happening in protected void paintSafely(Graphics g).

纸伞微斜 2024-08-18 09:23:34

看一下这个:http://code.google.com/p/xswingx/

顺便说一句,自己实现它并不是很难。几个监听器和自定义渲染器,瞧。

Take a look at this one: http://code.google.com/p/xswingx/

It is not very difficult to implement it by yourself, btw. A couple of listeners and custom renderer and voila.

梦回梦里 2024-08-18 09:23:34

对于任何 Swing 组件(即任何扩展 JComponent 的组件),您都可以调用 setToolTipText(String) 方法。

有关详细信息,请参考以下链接:

For any Swing component (that is, anything that extends JComponent), you can call the setToolTipText(String) method.

For more information, reference the following links:

陌路黄昏 2024-08-18 09:23:34

查看 WebLookAndFeel https://github.com/mgarin/weblaf/

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);

Have look at WebLookAndFeel at https://github.com/mgarin/weblaf/

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);
长亭外,古道边 2024-08-18 09:23:34

如果您仍在寻找解决方案,这里结合了其他答案(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");

If you still look for a solution, here's one that combined other answers (Bart Kiers and culmat) for your reference:

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");
你曾走过我的故事 2024-08-18 09:23:34

这可以通过使用焦点侦听器更新文本字段内容来实现。

使类实现焦点侦听器接口:

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 教程中。

This can be achieved by using a focus listener to update the text field content.

Make the class implement the focus listener interface:

class YourClass implements FocusListener

Add a method to catch when focus is gained that blanks the field:

public void focusGained(FocusEvent e) {
    if(JTextField1.getText().equals("Username")) {
        JTextField1.setText("");
    }
}

Add a method to catch when focus is lost to redisplay the default entry if the field was blank:

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
    }
}

Register your class as the focus listener for text field:

textField.addFocusListener(this);

Learn more at How to Write a Focus Listener in the Java Tutorials.

牵你的手,一向走下去 2024-08-18 09:23:34

这是一个基于 Adam Gawne-Cain 早期发布的完整示例。他的解决方案很简单,而且效果非常好。

我在多个字段的网格中使用了以下文本:

H__|__WWW__+__XXXX__+__WWW__|__H

这使得可以轻松验证提示文本的 x/y 对齐方式。

一些观察结果:
- 有很多解决方案,但许多只能表面上工作并且/或者有错误
- sun.tools.jconsole.ThreadTab.PromptingTextField 是一个简单的解决方案,但它仅在 Field 没有焦点时显示提示文本它是私人的,但没有什么是一点点剪切和粘贴就解决不了的。

以下内容适用于 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"));
    }
}

Here is a fully working example based on Adam Gawne-Cain's earlier Posting. His solution is simple and actually works exceptionally well.

I've used the following text in a Grid of multiple Fields:

H__|__WWW__+__XXXX__+__WWW__|__H

this makes it possible to easily verify the x/y alignment of the hinted text.

A couple of observations:
- there are any number of solutions out there, but many only work superficially and/or are buggy
- sun.tools.jconsole.ThreadTab.PromptingTextField is a simple solution, but it only shows the prompting text when the Field doesn't have the focus & it's private, but nothing a little cut-and-paste won't fix.

The following works on JDK 8 and upwards:

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"));
    }
}
面如桃花 2024-08-18 09:23:34

我创建了一个自定义类,当组件失去焦点且文本为空时,该类会在 JTextArea 内显示输入提示。此实现还可以防止听众收到显示提示文本时出现的不需要的通知。这可能也适用于 JTextFields,但我还没有测试过。

public class HintTextArea extends JTextArea{
    
    private static final long serialVersionUID = 1L;
    
    private String hintText;
    
    public HintTextArea(String hintText){
        
        super();
        this.hintText = hintText;
        
    }
    
    public String getHintText(){
        
        return hintText;
        
    }
    
    public void setHintText(String hintText){
        
        this.hintText = hintText;
        
    }
    
    @Override
    protected void paintComponent(Graphics g){
        
        boolean paintHint = getText().isEmpty() && !hasFocus();
        DocumentListener[] listeners;
        
        if(paintHint){
            
            listeners = getAndRemoveDocumentListeners();
            setText(hintText);
            super.paintComponent(g);
            setText("");
            restoreDocumentListeners(listeners);
            
        }else
            super.paintComponent(g);
        
    }
    
    protected DocumentListener[] getAndRemoveDocumentListeners(){
        
        PlainDocument document = (PlainDocument)getDocument();
        DocumentListener[] listeners = document.getDocumentListeners();
        
        for(DocumentListener listener : listeners)
            document.removeDocumentListener(listener);
        
        return listeners;
        
    }
    
    protected void restoreDocumentListeners(DocumentListener[] listeners){
        
        PlainDocument document = (PlainDocument)getDocument();
        
        for(DocumentListener listener : listeners)
            document.addDocumentListener(listener);
        
    }
    
}

I created a custom class that shows an input hint inside a JTextArea when the component is out of focus and the text is empty. This implementation also prevents listeners from receiving unwanted notifications that occur when the hint text is displayed. This may work for JTextFields as well but I haven't tested it.

public class HintTextArea extends JTextArea{
    
    private static final long serialVersionUID = 1L;
    
    private String hintText;
    
    public HintTextArea(String hintText){
        
        super();
        this.hintText = hintText;
        
    }
    
    public String getHintText(){
        
        return hintText;
        
    }
    
    public void setHintText(String hintText){
        
        this.hintText = hintText;
        
    }
    
    @Override
    protected void paintComponent(Graphics g){
        
        boolean paintHint = getText().isEmpty() && !hasFocus();
        DocumentListener[] listeners;
        
        if(paintHint){
            
            listeners = getAndRemoveDocumentListeners();
            setText(hintText);
            super.paintComponent(g);
            setText("");
            restoreDocumentListeners(listeners);
            
        }else
            super.paintComponent(g);
        
    }
    
    protected DocumentListener[] getAndRemoveDocumentListeners(){
        
        PlainDocument document = (PlainDocument)getDocument();
        DocumentListener[] listeners = document.getDocumentListeners();
        
        for(DocumentListener listener : listeners)
            document.removeDocumentListener(listener);
        
        return listeners;
        
    }
    
    protected void restoreDocumentListeners(DocumentListener[] listeners){
        
        PlainDocument document = (PlainDocument)getDocument();
        
        for(DocumentListener listener : listeners)
            document.addDocumentListener(listener);
        
    }
    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文