2012-04-05 19 views
11

Attualmente sto lavorando su una finestra della console in Swing. È basato su un JTextArea e funziona come una riga di comando comune. Digitare un comando in una riga e premere Invio. Nella riga successiva, l'output è mostrato e sotto quell'output, potresti scrivere il comando successivo.Rende non modificabili parti di un JTextArea (non l'intero JTextArea!)

Ora voglio, che è possibile modificare solo la riga corrente con il comando. Tutte le righe sopra (vecchi comandi e risultati) non dovrebbero essere modificabili. Come posso fare questo?

risposta

17

Non è necessario creare il proprio componente.

Questo può essere fatto (come in Ho fatto) utilizzando un numero personalizzato DocumentFilter.

È possibile ottenere il documento da textPane.getDocument() e impostare un filtro su di esso da document.setFilter(). All'interno del filtro, è possibile controllare la posizione del prompt e consentire modifiche solo se la posizione è successiva al prompt.

Ad esempio:

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); 
     } 
    } 
} 

Tuttavia, questo si impedisce di programmazione inserendo contenuti nella sezione di uscita (non modificabile) del terminale. Quello che puoi fare è invece un flag di passthrough sul filtro che imposti quando stai per aggiungere l'output, o (cosa ho fatto) imposta il filtro del documento su null prima di accodare l'output, e quindi resettarlo quando tu fatto.

+1

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

0

per quanto ne so, è necessario implementare il proprio controllo

Forse si potrebbe simulare con un elenco di campi di testo (anche abilitati e dispari disabili) o un mix di campi di testo/etichette

EDIT:

Scommetto per una textarea non modificabile e un campo di testo modificabile. Digitare il campo di testo, premere Invio, aggiungere "comando" e inviare alla textarea

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

Che dire che, quando ">>" è l'inizio di ogni riga nella riga di comando in cui l'utente può inserire 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 per keyListener -far troppo basso livello per soddisfare i requisiti in modo sicuro – kleopatra

+2

+1 KeyListener è il modo più semplice per implementare tale funzionalità, non ci sono problemi di sicurezza che utilizzo KeyListener da anni. – ShadowDoom

0

Questa è la mia implemitation di una recitazione filtro di documento come console in java. Tuttavia con alcune modifiche che mi consentono di avere una "area comandi" e una "area registro", vale a dire i risultati dei comandi di stampa nell'area del registro e il comando effettivo viene stampato nell'area comandi. L'area del registro è solo un'altra area di Jtext non editabile. Ho trovato che Thisthread è stato utile, quindi qualcuno che cerca di ottenere qualcosa di simile a questa implementazione può trovare alcuni suggerimenti!

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); 
     } 
    } 
}