¿Selección limitada en un JTextField / JTextComponent?

Considere un JFormattedTextField (o cualquier JTextComponent, en realidad) donde hay un prefijo y un sufijo visualizados alrededor de lo que es el “texto” real del campo.

Por ejemplo, el doble 3.5 sería la cadena (a través del formato) “3.50” alrededor de la cual sería el prefijo “$” y el sufijo “”, para un texto en pantalla de “$ 3.50”.

Claramente, esto es simple de hacer. Sin embargo, el usuario aún puede seleccionar texto dentro del prefijo / sufijo, por lo que es concebible que eliminen una parte o la totalidad del prefijo / sufijo. Preferiría que el usuario se restrinja de modo que el prefijo / sufijo no pueda seleccionarse en absoluto (aunque siga siendo parte del campo de texto, por lo que no hay JLabels). Casi puedo lograr esto con un CaretListener (o anulando setCaretPosition / moveCaretPosition), que evita que un Ca seleccione todo el campo, y evita que las teclas de flecha se muevan al prefijo / sufijo. Sin embargo, las teclas de arrastre del mouse y de flecha de desplazamiento aún permiten que la selección se mueva a estas áreas restringidas.

¿Algunas ideas?

Puede usar un filtro de navegación para esto.

Aquí hay un ejemplo para comenzar:

import java.awt.event.*; import javax.swing.*; import javax.swing.text.*; public class NavigationFilterPrefixWithBackspace extends NavigationFilter { private int prefixLength; private Action deletePrevious; public NavigationFilterPrefixWithBackspace(int prefixLength, JTextComponent component) { this.prefixLength = prefixLength; deletePrevious = component.getActionMap().get("delete-previous"); component.getActionMap().put("delete-previous", new BackspaceAction()); component.setCaretPosition(prefixLength); } public void setDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) { fb.setDot(Math.max(dot, prefixLength), bias); } public void moveDot(NavigationFilter.FilterBypass fb, int dot, Position.Bias bias) { fb.moveDot(Math.max(dot, prefixLength), bias); } class BackspaceAction extends AbstractAction { public void actionPerformed(ActionEvent e) { JTextComponent component = (JTextComponent)e.getSource(); if (component.getCaretPosition() > prefixLength) { deletePrevious.actionPerformed( null ); } } } public static void main(String args[]) throws Exception { JTextField textField = new JTextField("Prefix_", 20); textField.setNavigationFilter( new NavigationFilterPrefixWithBackspace(7, textField) ); JFrame frame = new JFrame("Navigation Filter Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(textField); frame.pack(); frame.setLocationRelativeTo( null ); frame.setVisible(true); } } 

Creo que así es como funciona JFormattedTextField. Así que no estoy seguro si puede usar esto con un campo de texto formateado ya que puede reemplazar el comportamiento predeterminado.