JHintingTextField - JTextField mit Prompt oder Eingabehinweis

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen

Aus Formularen in Webseiten kennt man oft Textfelder, die bereits einen grauen Text enthalten, der dem Benutzer ein Muster oder Hinweis für die Art des einzugebenen Inhalts anzeigt. Im Folgenden zeigt Sebastian Haufe (Ebenius), eine sehr elegante Lösung der Funktion, die auch in Swing funktioniert und auch aus der JXTextField-Komponente aus SwingX bekannt sein dürfte.

In seiner Lösung bleibt das Document (Model des JTextFields) unberührt. Das JTextField ist ja eigentlich leer und trotzdem wird Inhalt angezeigt. Der Hinweis wird in einem Highlighter gezeichnet.

/* (@)JHintingTextField.java */

 /* Copyright 2009 Sebastian Haufe

* Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.ebenius.widget;

import java.awt.*;

import javax.swing.*;
import javax.swing.text.*;


import javax.swing.text.Highlighter.HighlightPainter;

/**
* An enhanced text field, showing an {@link #getEmptyTextHint() empty text}
* hint on its view, if the {@link #getText() text content} is empty.
*
* @version $Revision: 1.1 $ as of $Date: 2009/04/08 19:13:04 $
* @author Sebastian Haufe
*/
public class JHintingTextField extends JTextField {

    /**
     * Serial version UID
     */
    private static final long serialVersionUID = 5061790840224877676L;

// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
    /**
     * Creates a new <code>JHintingTextField</code>.
     */
    public JHintingTextField() {
        installHighlightPainter();
    }

    /**
     * Creates a new <code>JHintingTextField</code>.
     *
     * @param columns the number of preferred columns to calculate preferred
     * width
     */
    public JHintingTextField(int columns) {
        super(columns);
        installHighlightPainter();
    }

    /**
     * Creates a new <code>JHintingTextField</code>.
     *
     * @param text the text to show in the text field
     */
    public JHintingTextField(String text) {
        super(text);
        installHighlightPainter();
    }

    /**
     * Creates a new <code>JHintingTextField</code>.
     *
     * @param text the text to show in the text field
     * @param columns the number of preferred columns to calculate preferred
     * width
     */
    public JHintingTextField(String text, int columns) {
        super(text, columns);
        installHighlightPainter();
    }

    /**
     * Creates a new <code>JHintingTextField</code>.
     *
     * @param doc the text model
     * @param text the text to show in the text field
     * @param columns the number of preferred columns to calculate preferred
     * width
     */
    public JHintingTextField(Document doc, String text, int columns) {
        super(doc, text, columns);
        installHighlightPainter();
    }

// -------------------------------------------------------------------------
// Hinting highlighter code
// -------------------------------------------------------------------------
    private void installHighlightPainter() {
        Highlighter highlighter = getHighlighter();
        System.out.println(highlighter);
        try {
            highlighter.addHighlight(0, 0, createHighlightPainter());
        } catch (BadLocationException ex) {
            assert false : "0:0 illegal?"; //$NON-NLS-1$
        }
    }

    protected HighlightPainter createHighlightPainter() {
        return new Highlighter.HighlightPainter() {

            final JLabel label = new JLabel("", //$NON-NLS-1$
                    SwingConstants.TRAILING);
            final int gap = 3;

            public void paint(
                    Graphics g,
                    int p0,
                    int p1,
                    Shape bounds,
                    JTextComponent c) {
                final String hint = (String) c.getClientProperty( //
                        "emptyTextHint"); //$NON-NLS-1$
                if (hint == null
                        || hint.length() == 0
                        || c.getDocument().getLength() != 0) {
                    return;
                }
                label.setText(hint);

                final Insets ins = c.getInsets();
                final boolean ltr = c.getComponentOrientation().isLeftToRight();
                if (ltr) {
                    ins.right += gap;
                } else {
                    ins.left += gap;
                }

                final Dimension pref = label.getPreferredSize();
                final int prHeight = pref.height;
                final int prWidth = pref.width;
                final int w = Math.min(c.getWidth() - ins.left - ins.right, prWidth);
                final int h = Math.min(c.getWidth() - ins.top - ins.bottom, prHeight);
                final int x = ltr ? c.getWidth() - ins.right - w : ins.left;
                final int parentHeight = c.getHeight() - ins.top - ins.bottom;
                final int y = ins.top + (parentHeight - h) / 2;
                label.setForeground(Color.GRAY);
                label.setOpaque(false);
                SwingUtilities.paintComponent(g, label, c, x, y, w, h);
            }
        };
    }

// -------------------------------------------------------------------------
// Bean getters and setters
// -------------------------------------------------------------------------
    /**
     * Returns the emptyTextHint.
     *
     * @return the emptyTextHint
     */
    public String getEmptyTextHint() {
        return (String) getClientProperty("emptyTextHint"); //$NON-NLS-1$
    }

    /**
     * Sets the emptyTextHint.
     *
     * @param hint the emptyTextHint to set
     */
    public void setEmptyTextHint(String hint) {
        putClientProperty("emptyTextHint", hint); //$NON-NLS-1$
        repaint();
    }
}

Zu testen mit diesem Code:

public static void main(String[] args) {
   final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
   final JHintingTextField comp = new JHintingTextField(20);
   comp.putClientProperty("emptyTextHint", "Name, Vorname");
   contentPane.add(comp);
   contentPane.add(new JButton("Dummy"), BorderLayout.LINE_END);

   final JFrame f = new JFrame("Test Frame: JHintingTextField");
   f.setContentPane(contentPane);
   f.pack();
   f.setLocationRelativeTo(null);
   f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
   f.setVisible(true);
}