2012-04-05 17 views
11

Actualmente estoy trabajando en una ventana de consola en Swing. Está basado en un JTextArea y funciona como una línea de comando común. Escribe un comando en una línea y presiona enter. En la siguiente línea, se muestra la salida y debajo de esa salida, puede escribir el siguiente comando.Hacer que las partes de un JTextArea no se puedan editar (¡no todo el JTextArea!)

Ahora quiero que solo pueda editar la línea actual con su comando. Todas las líneas anteriores (comandos y resultados anteriores) no deben ser editables. ¿Cómo puedo hacer esto?

Respuesta

17

No necesita crear su propio componente.

Esto se puede hacer (como en I've done) utilizando un DocumentFilter personalizado.

Puede obtener el documento de textPane.getDocument() y establecer un filtro en él por document.setFilter(). Dentro del filtro, puede verificar la posición de la solicitud y solo permitir modificaciones si la posición es posterior al aviso.

Por ejemplo:

private class Filter extends DocumentFilter { 
    public void insertString(final FilterBypass fb, final int offset, final String string, final AttributeSet attr) 
      throws BadLocationException { 
     if (offset >= promptPosition) { 
      super.insertString(fb, offset, string, attr); 
     } 
    } 

    public void remove(final FilterBypass fb, final int offset, final int length) throws BadLocationException { 
     if (offset >= promptPosition) { 
      super.remove(fb, offset, length); 
     } 
    } 

    public void replace(final FilterBypass fb, final int offset, final int length, final String text, final AttributeSet attrs) 
      throws BadLocationException { 
     if (offset >= promptPosition) { 
      super.replace(fb, offset, length, text, attrs); 
     } 
    } 
} 

Sin embargo, esto le impide insertar mediante programación contenidos en la sección de salida (no editable) del terminal. Lo que puede hacer en su lugar es un indicador de paso en su filtro que usted configura cuando está a punto de agregar el resultado, o (lo que hice) establecer el filtro de documento en nulo antes de anexar la salida, y luego reiniciarlo cuando ' re hecho.

+1

((AbstractDocument) jta.getDocument()). SetDocumentFilter (dfilter); –

0

yo sepa, lo que necesita para implementar su propio control

Tal vez usted podría simular con una lista de campos de texto (incluso habilitados e impares desactivado) o una mezcla de campos de texto/etiquetas

EDIT:

Apostaría por un área de texto no editable y un campo de texto editable. Escriba en textfield, presione enter, agregue "command" y salga al área de texto

3
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.text.*; 
public class OnlyEditCurrentLineTest { 
    public JComponent makeUI() { 
    JTextArea textArea = new JTextArea(8,0); 
    textArea.setText("> aaa\n> "); 
    ((AbstractDocument)textArea.getDocument()).setDocumentFilter(
     new NonEditableLineDocumentFilter()); 
    JPanel p = new JPanel(new BorderLayout()); 
    p.add(new JScrollPane(textArea), BorderLayout.NORTH); 
    return p; 
    } 
    public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     @Override public void run() { createAndShowGUI(); } 
    }); 
    } 
    public static void createAndShowGUI() { 
    JFrame f = new JFrame(); 
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    f.getContentPane().add(new OnlyEditCurrentLineTest().makeUI()); 
    f.setSize(320,240); 
    f.setLocationRelativeTo(null); 
    f.setVisible(true); 
    } 
} 
class NonEditableLineDocumentFilter extends DocumentFilter { 
    @Override public void insertString(
     DocumentFilter.FilterBypass fb, int offset, String string, 
     AttributeSet attr) throws BadLocationException { 
    if(string == null) { 
     return; 
    }else{ 
     replace(fb, offset, 0, string, attr); 
    } 
    } 
    @Override public void remove(
     DocumentFilter.FilterBypass fb, int offset, 
     int length) throws BadLocationException { 
    replace(fb, offset, length, "", null); 
    } 
    private static final String PROMPT = "> "; 
    @Override public void replace(
     DocumentFilter.FilterBypass fb, int offset, int length, 
     String text, AttributeSet attrs) throws BadLocationException { 
    Document doc = fb.getDocument(); 
    Element root = doc.getDefaultRootElement(); 
    int count = root.getElementCount(); 
    int index = root.getElementIndex(offset); 
    Element cur = root.getElement(index); 
    int promptPosition = cur.getStartOffset()+PROMPT.length(); 
    //As Reverend Gonzo says: 
    if(index==count-1 && offset-promptPosition>=0) { 
     if(text.equals("\n")) { 
     String cmd = doc.getText(promptPosition, offset-promptPosition); 
     if(cmd.isEmpty()) { 
      text = "\n"+PROMPT; 
     }else{ 
      text = "\n"+cmd+"\n xxxxxxxxxx\n" + PROMPT; 
     } 
     } 
     fb.replace(offset, length, text, attrs); 
    } 
    } 
} 
0

¿Qué hay de que, cuando ">>" es el comienzo de cada línea en la línea de comandos donde el usuario puede introducir un comando:

textArea.addKeyListener(new KeyAdapter() { 

    public void keyPressed(KeyEvent event) { 

     int code = event.getKeyCode();   
     int caret = textArea.getCaretPosition(); 
     int last = textArea.getText().lastIndexOf(">> ") + 3; 

     if(caret <= last) { 

      if(code == KeyEvent.VK_BACK_SPACE) { 

       textArea.append(" "); 

       textArea.setCaretPosition(last + 1); 
      } 

      textArea.setCaretPosition(textArea.getText().length()); 
     } 
    } 
}); 
+1

-1 para keyListener -demasiado bajo nivel para cumplir con los requisitos de manera segura – kleopatra

+2

+1 KeyListener es la forma más fácil de implementar dicha funcionalidad, no hay problemas de seguridad. He estado usando KeyListener desde hace años. – ShadowDoom

0

Ésta es mi implemitation de un filtro de actuación documento como una consola en java. Sin embargo, con algunas modificaciones que me permiten tener un "área de comando" y un "área de registro", lo que significa que los resultados de los comandos se imprimen en el área de registro y el comando real se imprime en el área de comando. El área de registro es solo otra área de Jtext que no es editable. Encontré que esto es útil, ¡así que si alguien intenta hacer algo similar a esta implementación puede encontrar algunos consejos!

class NonEditableLineDocumentFilter extends DocumentFilter 
{ 
    private static final String PROMPT = "Command> "; 

    @Override 
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string,AttributeSet attr) throws BadLocationException 
    { 
     if(string == null) 
     { 
      return; 
     } 
     else 
     { 
      replace(fb, offset, 0, string, attr); 
     } 
    } 

    @Override 
    public void remove(DocumentFilter.FilterBypass fb, int offset,int length) throws BadLocationException 
    { 
     replace(fb, offset, length, "", null); 
    } 

    @Override 
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length,String text, AttributeSet attrs) throws BadLocationException 
    {  
     Document doc = fb.getDocument(); 
     Element root = doc.getDefaultRootElement(); 
     int count = root.getElementCount(); 
     int index = root.getElementIndex(offset); 
     Element cur = root.getElement(index); 
     int promptPosition = cur.getStartOffset()+PROMPT.length(); 

     if(index==count-1 && offset-promptPosition>=0) 
     { 
      if(text.equals("\n")) 
      { 
       cmd = doc.getText(promptPosition, offset-promptPosition); 

       if(cmd.trim().isEmpty()) 
       { 
        text = "\n"+PROMPT; 
       } 
       else 
       { 
        text = "\n" + PROMPT; 
       } 
      } 
      fb.replace(offset, length, text, attrs); 
     } 
    } 
} 
Cuestiones relacionadas