2010-11-28 22 views
11

Tengo un componente JTextArea dentro de JScrollPane y el área de texto no se puede editar. Me gustaría habilitar el desplazamiento del área de texto con las teclas de flecha hacia arriba y hacia abajo (es decir, al presionar las teclas de flecha se desplazará el área de texto por una línea). ¿Alguna idea de cómo lograr esto?Desplazamiento de JScrollPane con las teclas de flecha

+1

Sé que ha aceptado una respuesta, pero no siempre es necesario escribir un código personalizado. Mira mi sugerencia recién agregada. – camickr

+0

Sí, al combinar el conocimiento de ambas respuestas, este tipo de problemas pueden resolverse muy bien. Desafortunadamente no es posible aceptar múltiples respuestas; ( – JooMing

Respuesta

13

Sí Configuración de las teclas es el camino a seguir, pero no siempre se necesita para crear sus propias acciones. Los componentes Swing vienen con acciones predeterminadas que a menudo puede reutilizar.

Consulte Key Bindings para obtener una lista completa de estas acciones.

Ahora que se conoce el nombre de la acción sólo puede obligar a éste a una combinación de teclas:

JScrollBar vertical = scrollPane.getVerticalScrollBar(); 
InputMap im = vertical.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 
im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement"); 
im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement"); 
+0

De hecho, gracias como siempre por la información útil. –

+0

¡Gracias, este enlace para enlaces de teclas es muy útil! La reutilización de acciones preexistentes hace que el código sea mucho más fácil de mantener. – JooMing

0

Debe agregar KeyListener a su JScrollPane.

+1

Casi siempre es mejor usar el enlace de teclas que un oyente de teclas en este tipo de situaciones. –

4

Si el JTextArea no es editable y no se puede enfocar, no responderá a las teclas de flecha. No estoy seguro de si hay una forma canónica de evitar esto, pero una forma de hacerlo responder es establecer su enlace de clave para responder a las teclas hacia arriba y hacia abajo cuando JTextArea se encuentra en la ventana enfocable. Un ejemplo de esto es la siguiente:

import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 

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

@SuppressWarnings("serial") 
public class TestScrollingArea extends JPanel { 
    private static final String UP = "Up"; 
    private static final String DOWN = "Down"; 
    private JTextArea area = new JTextArea(20, 40); 
    private JScrollPane scrollPane = new JScrollPane(area); 

    public TestScrollingArea() { 
     // make textarea non-editable and non-focusable 
     area.setEditable(false); 
     area.setFocusable(false); 
     area.setWrapStyleWord(true); 
     area.setLineWrap(true); 
     add(scrollPane); 

     // fill area with letters 
     for (int i = 0; i < 10; i++) { 
      for (int j = 0; j < 100; j++) { 
       area.append("abcdefg "); 
      } 
     } 

     // have JTextArea tell us how tall a line of text is. 
     int scrollableIncrement = area.getScrollableUnitIncrement(scrollPane.getVisibleRect(), 
        SwingConstants.VERTICAL, 1); 

     // add key bindings to the JTextArea 
     int condition = JTextComponent.WHEN_IN_FOCUSED_WINDOW; 
     InputMap inMap = area.getInputMap(condition); 
     ActionMap actMap = area.getActionMap(); 

     inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), UP); 
     inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), DOWN); 
     actMap.put(UP, new UpDownAction(UP, scrollPane.getVerticalScrollBar().getModel(), 
        scrollableIncrement)); 
     actMap.put(DOWN, new UpDownAction(DOWN, scrollPane.getVerticalScrollBar().getModel(), 
        scrollableIncrement)); 

    } 

    // Action for our key binding to perform when bound event occurs 
    private class UpDownAction extends AbstractAction { 
     private BoundedRangeModel vScrollBarModel; 
     private int scrollableIncrement; 
     public UpDownAction(String name, BoundedRangeModel model, int scrollableIncrement) { 
      super(name); 
      this.vScrollBarModel = model; 
      this.scrollableIncrement = scrollableIncrement; 
     } 

     @Override 
     public void actionPerformed(ActionEvent ae) { 
      String name = getValue(AbstractAction.NAME).toString(); 
      int value = vScrollBarModel.getValue(); 
      if (name.equals(UP)) { 
       value -= scrollableIncrement; 
       vScrollBarModel.setValue(value); 
      } else if (name.equals(DOWN)) { 
       value += scrollableIncrement; 
       vScrollBarModel.setValue(value); 
      } 
     } 
    } 

    private static void createAndShowUI() { 
     JFrame frame = new JFrame("TestScrollingArea"); 
     frame.getContentPane().add(new TestScrollingArea()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

¡Genial! Un pequeño problema fue que las teclas de page/pagedown no funcionaban. Lo conseguí trabajando por configurando el área de texto como enfocable y utilizando el mapa de entrada para WHEN_FOCUSED en lugar de WHEN_IN_FOCUSED_WINDOW. Muchas gracias! – JooMing

+0

O la página arriba y la página pueden agregarse como enlaces de tecla igual que el anterior, excepto que el incremento/decremento será el alto de la ventana gráfica. –

+1

No siempre es necesario crear una acción personalizada. Consulte mi sugerencia. – camickr

0

encontré con este problema y si bien las respuestas fue útil en la que me conduce a la dirección correcta algunas partes de la solución puede haber cambiado desde entonces. Me funcionó con los siguientes cambios: - fue el InputMap de la instancia de JScrollPane que tuvo que ser cambiado - actionMapKeys tenía que ser: "unitScrollX" y/o "scrollX" (X = Abajo, Arriba, Izquierda, Derecha) . Ellos residen en BasicScrollPaneUI.

Cuestiones relacionadas