7

I am looking for a way to put example text into a swing JTextField and have it grayed out. The example text should then disappear as soon as any thing is entered into that text field. Some what similar to what stackoverflow does when a user is posting a question with the title field.

I would like it if it was already a extended implementation of JTextField so that I can just drop it in as a simple replacement. Anything from swingx would work. I guess if there is not an easy way to do this my option will probably be to override the paint method of JTextField do something that way maybe.

Thanks

startoftext
  • 3,846
  • 7
  • 40
  • 49

7 Answers7

7

The Text Prompt class provides the required functionality without using a custom JTextField.

It allows you to specify a prompt that is displayed when the text field is empty. As soon as you type text the prompt is removed.

The prompt is actually a JLabel so you can customize the font, style, colour, transparency etc..:

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

Some examples of customizing the look of the prompt:

enter image description here

camickr
  • 321,443
  • 19
  • 166
  • 288
5

If you can use external librairies, the Swing components from Jide software have what you are looking for; it's called LabeledTextField (javadoc) and it's part of the JIDE Common Layer (Open Source Project) - which is free. It's doing what mklhmnn suggested.

Daniel Teply
  • 1,974
  • 1
  • 13
  • 10
3

How about initialize the text field with default text and give it a focus listener such that when focus is gained, if the text .equals the default text, call selectAll() on the JTextField.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
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);
    }
}
ignis
  • 8,692
  • 2
  • 23
  • 20
  • not, never ever, don't to create whatever inside paintComponent, not JComponents, all Objects must be prepared, just to invoke Graphics/2D methods, not never to change its properties too – mKorbel Nov 03 '12 at 09:14
  • @mKorbel: why? Can you elaborate or give a reference? – ignis Nov 03 '12 at 09:19
  • 1
    bacause paintComponent are called 1. internally when JComponent required for repaint(), 2. after call repaint(), 3. from every mouse and Keyboard events, 4. when Hierarchy or Container (add JComponents, resize e.i.) are changed or fired events programatically, 5. should be upto latency in Native OS (overloading this refresh ratio to freeze painting), 6 each or this event to create a new JLabel, have to calculating with OutOfMemoryExceptions too, 7, the same issue don't load image from this block, prepare that as local variable and only pickup from array or by variable name – mKorbel Nov 03 '12 at 09:31
  • @mKorbel: Moved the JLabel outside, thank you for pointing it out. – ignis Nov 03 '12 at 09:34
  • @mKorbel: Debugging shows that the current paintComponent() overhead is inappreciable on most invocations. Now I call setBounds() only when they have changed (so the EDT gets frozen the same amount of time as if setBounds() were done outside). – ignis Nov 03 '12 at 10:30
  • start Swing Timer and on some period repaint() contents periodically, there are a bunch of code about by (@MadProgrammer == most active last time) or (@Hovercraft Full Of Eels == great examples with excelent descriptions about), everything there by my person cloud be useless in compare with ... – mKorbel Nov 03 '12 at 10:50
2

Rather than overriding, put a value in the field and add a KeyListener that would remove the value when a key stroke is registered. Maybe also have it change the foreground.

You could wrap this up into your own custom JTextField class that would take the default text in a constructor.

jzd
  • 23,473
  • 9
  • 54
  • 76
  • You can't use a key listener as data can be entered by other methods such as by copy and paste. – Hovercraft Full Of Eels Feb 18 '11 at 18:01
  • I wouldn't actually add this example text in the value field as there is then a risk of using the getText() retrieving that example text – dm76 Feb 18 '11 at 18:01
  • @Hover, I thought about a focus listener first, but in the SO title example that the OP mentioned as an example, the text does not disappear on focus but instead when you start typing. If you did allow pasting a adding a DocumentListener might be a better solution. – jzd Feb 18 '11 at 19:24
  • @DavidM, the getText() method could be overridden to prevent the example text from being returned if it had not been typed. – jzd Feb 18 '11 at 19:25
1

You can't do that with a plain text field, but you can put a disabled JLabel on top of the JTextField and hide it if the text field gets the focus.

Mot
  • 28,248
  • 23
  • 84
  • 121
1

Do it like this:

  1. Define the string with the initial text you like and set up your TextField:

    String initialText = "Enter your initial text here";
    jTextField1.setText(initialText);
    
  2. Add a Focus Listener to your TextField, which selects the entire contents of the TextField if it still has the initial value. Anything you may type in will replace the entire contents, since it is selected.

    jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
        public void focusGained(java.awt.event.FocusEvent evt) {
           if (jTextField1.getText().equals(initialText)) {
              jTextField1.selectAll();
           }
        }
    });
    
Costis Aivalis
  • 13,680
  • 3
  • 46
  • 47