Swing PlaceHolderText

Dagobert

Bekanntes Mitglied
Guten Abend,
Ich habe mir gerade mal auf die schnelle ein Placeholder-Textfeld zusammengebaut....
Jetzt möchte ich gerne eure Meinung dazu hören, und noch eine Frage stellen. Wie kann ich die passende Höhe für mein Text ermitteln?

Java:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * Ein Textfeld mit einem Placeholder
 * @author Dagobert
 * @since 28.04.2012
 * @version 1.0
 */
@SuppressWarnings("serial")
public class PlaceHolder extends JTextField implements FocusListener{
	/**
	 * Der Text der angezeigt werden soll, wenn das Feld leer ist
	 */
	private String placeHolderText;
	/**
	 * Die verschiedenen Farben
	 */
	private Color normale, placeHolder;
	/**
	 * Ob der Placeholder gerade angezeigt wird
	 */
	private boolean placeholdervisible;
	
	public PlaceHolder(String placeHolderText){
		super(20);
		
		normale = Color.black;
		placeHolder = Color.gray;
		
		setPlaceHolder(placeHolderText);
		showPlaceHolder();
		
		validate();
		
		addFocusListener(this);
	}
	
	
	/**
	 * Setzt einen Placeholder-Text
	 * @param placeHolderText
	 */
	public void setPlaceHolder(final String placeHolderText){
		this.placeHolderText = placeHolderText;
	}
	
	/**
	 * Zeigt den Placeholder an
	 */
	public void showPlaceHolder(){
		placeholdervisible = true;
	}
	
	
	/**
	 * Versteckt den Placeholder
	 */
	public void hidePlaceHolder(){
		placeholdervisible = false;
	}
	
	
	// Wenn der Placeholder sichtbar ist, und der Fokus erlangt wird, wird der Placeholder versteckt
	@Override
	public void focusGained(FocusEvent e) {
		if(placeholdervisible)
			hidePlaceHolder();
	}
	
	// Wenn der Text leer ist, und der Fokus verloren geht, dann soll der Text angezeigt werden
	@Override
	public void focusLost(FocusEvent e) {
		if(getText().length() == 0)
			showPlaceHolder();
	}
	
	// Zeichnet den Placeholder wenn er aktiv ist
	@Override
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		g.setColor(normale);
		if(placeholdervisible || getText().length() == 0){
			g.setColor(placeHolder);
			g.drawString(placeHolderText, 3, (getHeight()/2)+5);
		}
	}
	
	public static void main(String arg[]){
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel panel = new JPanel();
		
		final PlaceHolder p = new PlaceHolder("TestPlaceHolder");
		panel.add(p);
		JButton b = new JButton("Abfragen");
		b.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				System.out.println(p.getText());
			}
		});
		panel.add(b);
		
		panel.validate();
		frame.add(panel);
		frame.validate();
		frame.pack();
		frame.setVisible(true);
	}
}

mfg. Dagobert
 
V

vanny

Gast
Die frage ist jawol eher, was hast du vor?

PlaceHolder = Platzhalter, soweit kann ich folgen und nu?
 

Dagobert

Bekanntes Mitglied
Was ich vor habe, ist einfach ein Beispieltext einer Eingabe anzeigen, wenn der Benutzer noch nix eingegeben hat.

Ich wollte wissen ob die Ausführung so okay ist, oder was man java-technisch besser machen könnte.
Und wie ich das Textfeld mittig beim zeichnen treffe, denn so wie es jetzt ist, ist es nicht mittig :D

mfg. Dagobert
 
Zuletzt bearbeitet:
V

vanny

Gast
naja das geht auch einfacher.
Du kannst deinem JTextField mit #setText("Der Beispieltext"); einfach den Beispieltext zuweisen.
Ich löse das dann immer so, dass ich vor der Benutzereingabe den Text nicht schwarz sondern lightgrey mache und per FocusListener bei focusGained(); die Textfarbe wieder auf schwarz und per slectAll();
den kompletten Beispieltext markiere.
Bei focusLost(); prüfe ich dann, ob eine gültige Eingabe erfolgt ist. Um das TextField etweder wieder auf, wie du´s nennst PlaceHolder zu setzen oder halt "normal" zu lassen.(das lässt sich beim nächsten focusGained(); dann easy abfragen)

Gruß Vanny
 

xehpuk

Top Contributor
Und wie ich das Textfeld mittig beim zeichnen treffe, denn so wie es jetzt ist, ist es nicht mittig :D
Schwierig. Da geschieht viel Magie in den Tiefen der TextUI.
Ich nutze in meinem folgenden Beispiel
Code:
BasicTextUI.modelToView()
und
Code:
JComponent.getInsets()
, um an die x- und y-Koordinaten zu kommen. Ist auch noch nicht perfekt, da es anscheinend manchmal um 1 px abweicht.
Vielleicht ists aber eine kleine Inspiration:
Java:
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

/**
 * @author xehpuk
 */
public class PlaceholderTextField extends JTextField {
	private static final long serialVersionUID = -5529071085971698388L;

	/**
	 * The placeholder to be displayed if the text field is empty.
	 */
	private String placeholder;
	/**
	 * Determines whether the placeholder should be displayed even on focus.
	 */
	private boolean paintingOnFocus;
	/**
	 * The color the placeholder should be displayed in.
	 */
	private Color placeholderColor;

	public String getPlaceholder() {
		return placeholder;
	}

	public void setPlaceholder(final String placeholder) {
		this.placeholder = placeholder;
		repaint();
	}
	
	public boolean isPaintingOnFocus() {
		return paintingOnFocus;
	}

	public void setPaintingOnFocus(final boolean paintingOnFocus) {
		this.paintingOnFocus = paintingOnFocus;
		repaint();
	}

	public Color getPlaceholderColor() {
		return placeholderColor;
	}

	public void setPlaceholderColor(final Color placeholderColor) {
		this.placeholderColor = placeholderColor;
		repaint();
	}

	public PlaceholderTextField() {
		super();
	}

	public PlaceholderTextField(final Document doc, final String text, final int columns) {
		super(doc, text, columns);
	}

	public PlaceholderTextField(final int columns) {
		super(columns);
	}

	public PlaceholderTextField(final String text, final int columns) {
		super(text, columns);
	}

	public PlaceholderTextField(final String text) {
		super(text);
	}

	{
		addFocusListener(new RepaintFocusListener());
	}

	@Override
	protected void paintComponent(final Graphics g) {
		super.paintComponent(g);
		if (getPlaceholder() != null && getText().isEmpty() && (isPaintingOnFocus() || !isFocusOwner())) {
			try {
				final BasicTextFieldUI ui = (BasicTextFieldUI) getUI();
				final Rectangle rect = ui.modelToView(this, 0);
				final Insets insets = getInsets();
				g.setFont(getFont());
				g.setColor(getPlaceholderColor() == null ? getForeground() : getPlaceholderColor());
				((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
				g.drawString(getPlaceholder(), rect.x, getHeight() - insets.top - insets.bottom - rect.y);
			} catch (final BadLocationException e) {
				e.printStackTrace();
			}
		}
	}

	private class RepaintFocusListener implements FocusListener {
		@Override
		public void focusGained(final FocusEvent e) {
			repaint();
		}

		@Override
		public void focusLost(final FocusEvent e) {
			repaint();
		}
	}
}

class PlaceholderTextFieldTest {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				final JFrame frame = new JFrame("Placeholder test");
				final PlaceholderTextField field = new PlaceholderTextField(10);
				field.setFont(field.getFont().deriveFont(20f));
				field.setPlaceholder("Placeholder");
				field.setPaintingOnFocus(true);
				field.setPlaceholderColor(Color.GRAY);
				frame.setLayout(new FlowLayout());
				frame.add(field);
				frame.add(new JButton("OK"));
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.pack();
				frame.setLocationRelativeTo(null);
				frame.setVisible(true);
			}
		});
	}
}

naja das geht auch einfacher.
Einfacher und schlechter. Was du da beschreibst, ist in meinen Augen ein übler Hack. Ein Platzhaltertext gehört letztendlich in die View, du hingegen arbeitest mit dem Document, also Model.
 

Neue Themen


Oben