JTextField 中的示例文本

7

我正在寻找一种方法,可以在swing JTextField中放置示例文本并使其变灰。只要在该文本字段中输入任何内容,示例文本就应该会消失。与stackoverflow在用户发布标题字段的问题时所做的操作有些相似。

如果它已经是JTextField的扩展实现,那将很好,这样我就可以轻松地用它来替换原有的文本字段。来自swingx的任何内容都可以使用。如果没有简单的方法来完成此操作,我的选项可能就是覆盖JTextField的paint方法,以便以这种方式进行操作。

谢谢

7个回答

7

文本提示类提供所需功能,无需使用自定义的JTextField。

它允许您指定在文本字段为空时显示的提示。一旦输入文本,提示将被删除。

提示实际上是一个JLabel,因此您可以自定义字体、样式、颜色、透明度等:

JTextField tf7 = new JTextField(10);
TextPrompt tp7 = new TextPrompt("First Name", tf7);
tp7.setForeground( Color.RED );

一些自定义提示外观的示例: enter image description here

5
如果您可以使用外部库,Jide software的Swing组件具有您寻找的功能;它被称为LabeledTextField (javadoc),是JIDE Common Layer(开源项目)的一部分 - 是免费的。它正在执行mklhmnn建议的操作。

3

如何使用默认文本初始化文本字段,并添加焦点监听器,使得当焦点被获取时,如果文本等于默认文本,则在JTextField上调用selectAll()方法。


2
private JLabel l;

JPromptTextField(String prompt) {
    l = new JLabel(prompt, SwingConstants.CENTER);
    l.setForeground(Color.GRAY);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    if (this.getText().length() == 0) {
        // Reshape the label if needed, then paint

        final Rectangle mine = this.getBounds();
        final Rectangle its = l.getBounds(); 
        boolean resized = (mine.width != its.width) || (mine.height != its.height);
        boolean moved = (mine.x != its.x) || (mine.y != its.y);
        if (resized || moved)
            l.setBounds(mine);

        l.paint(g);
    }
}

不要在paintComponent内部创建任何东西,也不要使用JComponents,所有对象都必须准备好,只需调用Graphics/2D方法,绝对不能更改其属性。 - mKorbel
@mKorbel:为什么?你能详细说明或提供参考资料吗? - ignis
1
因为paintComponent方法会在以下情况下被调用:1.当JComponent需要重新绘制时,2.在调用repaint()后,3.从每个鼠标和键盘事件中,4.当层次结构或容器(添加JComponents,调整大小等)发生变化或以编程方式触发事件时,5.应该根据本地操作系统的延迟来确定刷新频率(过载此刷新频率会导致画面冻结),6.每个此类事件都要创建一个新的JLabel,并且还要考虑OutOfMemoryExceptions,7.不要从此块加载相同的图像,将其准备为局部变量,并仅通过数组或变量名进行提取。 - mKorbel
@mKorbel:将JLabel移动到外面,感谢您指出。 - ignis
@mKorbel:调试显示,大多数调用中当前的paintComponent()开销微不足道。现在我只在它们发生变化时调用setBounds()(因此EDT被冻结的时间与在外部执行setBounds()相同)。 - ignis
启动Swing计时器并在一定时间间隔内定期重绘()内容,有许多关于(@MadProgrammer == 最近最活跃)或(@Hovercraft Full Of Eels == 出色的描述和示例)的代码,与之相比,我个人的所有内容可能都是无用的... - mKorbel

2
不要覆盖现有值,将一个值放入字段中并添加一个 KeyListener,在注册按键时删除该值。也许还可以更改前景色。
你可以把这个操作封装到自己的定制 JTextField 类中,在构造函数中使用默认文本。

您不能使用按键监听器,因为数据可以通过其他方法输入,如复制和粘贴。 - Hovercraft Full Of Eels
我实际上不会将这个示例文本添加到值字段中,因为存在使用getText()检索该示例文本的风险。 - dm76
@Hover,我首先考虑到焦点侦听器,但在 OP 提到的 SO 标题示例中,文本并不会在焦点上消失,而是在您开始输入时消失。如果您允许粘贴和添加 DocumentListener 可能会是更好的解决方案。 - jzd
@DavidM,可以重写getText()方法以防止返回示例文本,如果它尚未被键入。 - jzd

1

像这样做:

  1. 定义一个字符串并设置为你喜欢的初始文本,然后设置你的TextField:

    String initialText = "在此输入初始文本";
    jTextField1.setText(initialText);
    
  2. 为你的TextField添加一个焦点监听器,如果它仍然有初始值,就选择整个内容。任何你输入的内容都会替换掉整个内容,因为它被选中了。

    jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
        public void focusGained(java.awt.event.FocusEvent evt) {
           if (jTextField1.getText().equals(initialText)) {
              jTextField1.selectAll();
           }
        }
    });
    

这正是Hovercraft建议的。我一直在忙着粘贴,没有看他的答案。 - Costis Aivalis

1

你不能使用普通文本字段来实现这个功能,但是你可以在 JTextField 上方放置一个禁用的 JLabel,并在文本字段获得焦点时隐藏它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接