2008-10-27 17 views
11

Mi Programa anula public void paint(Graphics g, int x, int y); con el fin de extraer algunas picaduras usando g.drawString(someString, x+10, y+30);Cómo salida de una cadena en varias líneas a través de Gráficos

Ahora someString puede ser bastante largo y por lo tanto, no puede caber en una línea.

¿Cuál es la mejor manera de escribir el texto en varias líneas.
Por ejemplo, en un rectángulo (x1, y1, x2, y2)?

Respuesta

9

Gracias a la sugerencia de Epaga y un par de ejemplos en la red (no tan obvio para encontrar! Usé principalmente Break a Line for text layout), podría hacer un componente para mostrar el texto envuelto. Está incompleto, pero al menos muestra el efecto deseado.

class TextContainer extends JPanel 
{ 
    private int m_width; 
    private int m_height; 
    private String m_text; 
    private AttributedCharacterIterator m_iterator; 
    private int m_start; 
    private int m_end; 

    public TextContainer(String text, int width, int height) 
    { 
     m_text = text; 
     m_width = width; 
     m_height = height; 

     AttributedString styledText = new AttributedString(text); 
     m_iterator = styledText.getIterator(); 
     m_start = m_iterator.getBeginIndex(); 
     m_end = m_iterator.getEndIndex(); 
    } 

    public String getText() 
    { 
     return m_text; 
    } 

    public Dimension getPreferredSize() 
    { 
     return new Dimension(m_width, m_height); 
    } 

    public void paint(Graphics g) 
    { 
     super.paintComponent(g); 

     Graphics2D g2 = (Graphics2D) g; 
     FontRenderContext frc = g2.getFontRenderContext(); 

     LineBreakMeasurer measurer = new LineBreakMeasurer(m_iterator, frc); 
     measurer.setPosition(m_start); 

     float x = 0, y = 0; 
     while (measurer.getPosition() < m_end) 
     { 
      TextLayout layout = measurer.nextLayout(m_width); 

      y += layout.getAscent(); 
      float dx = layout.isLeftToRight() ? 
        0 : m_width - layout.getAdvance(); 

      layout.draw(g2, x + dx, y); 
      y += layout.getDescent() + layout.getLeading(); 
     } 
    } 
} 

Sólo por diversión, lo hice un círculo apropiado (por desgracia, ninguna justificación, parece):

public void paint(Graphics g) 
{ 
    super.paintComponent(g); 

    Graphics2D g2 = (Graphics2D) g; 
    FontRenderContext frc = g2.getFontRenderContext(); 

    LineBreakMeasurer measurer = new LineBreakMeasurer(m_iterator, frc); 
    measurer.setPosition(m_start); 

    float y = 0; 
    while (measurer.getPosition() < m_end) 
    { 
     double ix = Math.sqrt((m_width/2 - y) * y); 
     float x = m_width/2.0F - (float) ix; 
     int width = (int) ix * 2; 

     TextLayout layout = measurer.nextLayout(width); 

     y += layout.getAscent(); 
     float dx = layout.isLeftToRight() ? 
       0 : width - layout.getAdvance(); 

     layout.draw(g2, x + dx, y); 
     y += layout.getDescent() + layout.getLeading(); 
    } 
} 

No estoy muy seguro de cómputo dx, sin embargo.

3

java.awt.font.TextLayout puede ser útil. He aquí un fragmento de su código de ejemplo:

Graphics2D g = ...; 
    Point2D loc = ...; 
    Font font = Font.getFont("Helvetica-bold-italic"); 
    FontRenderContext frc = g.getFontRenderContext(); 
    TextLayout layout = new TextLayout("This is a string", font, frc); 
    layout.draw(g, (float)loc.getX(), (float)loc.getY()); 

    Rectangle2D bounds = layout.getBounds(); 
    bounds.setRect(bounds.getX()+loc.getX(), 
        bounds.getY()+loc.getY(), 
        bounds.getWidth(), 
        bounds.getHeight()); 
    g.draw(bounds); 

De lo contrario siempre se puede utilizar un elemento de texto Swing para hacer el trabajo para usted, sólo tiene que pasar en los gráficos que desee para pintar en.

+0

Ya lo tengo. Mi problema es que no quiero un rectángulo alrededor del texto, sino el texto dentro de un rectángulo dado. – Burkhard

+0

Tenga en cuenta que el constructor de TextLayout, indocumentado, arroja una excepción si la cadena que pasa está vacía. –

+1

Usar \t Forma labelShape = textLayout1.getOutline (null); y luego g2d.fill (labelShape); deberían eliminar el borde – mk7

1

Construye incrementalmente tu cuerda, palabra por palabra, usando el método de Epaga para encontrar la longitud de tu cuerda. Una vez que la longitud es más larga que su rectángulo, elimine la última palabra e imprima. Repite hasta que te quedes sin palabras.

Parece un mal algoritmo, pero para cada línea, es realmente O (screenWidth/averageCharacterWidth) => O (1).

Aún así, use un StringBuffer para construir su cuerda!

+1

Esto no va a tener una complejidad de tiempo de O (1); O (n), tal vez, ya que necesita (al menos) agregar una palabra (es decir, agregar un número de caracteres en StringBuilder.append) hasta que se hayan agotado todos los caracteres. – jamesh

+0

Me parece que soy malo para expresarme correctamente ... Quiero decir que cada línea es O (1). Puede lanzar 1000 palabras, pero, para cada línea, dejará de agregar palabras en el borde de la pantalla. En general, sí, O (n). –

+0

Funciona solo si supones que la cadena estará en un máximo de 2 líneas, cuando sea más, no funcionará. –

0

Puede usar un JLabel e incrustar el texto con html.

JLabel.setText("<html>"+line1+"<br>"+line2); 
+0

Su HTML está siendo eliminado. Supongo que el primer literal de cadena es y el segundo es
. –

+1

¿No le hace daño al propósito si tiene que agregar sus propios linebreaks? –

1

tenido algunos problemas para mí este es mi solución:

Graphics2D g=.... 
FontRenderContext frc = g.getFontRenderContext(); 
TextLayout layout = new TextLayout(text, font, frc); 
String[] outputs = text.split("\n"); 
for(int i=0; i<outputs.length; i++){ 
    g.drawString(outputs[i], 15,(int) (15+i*layout.getBounds().getHeight()+0.5)); 

Espero que ayude .... sencilla pero funciona.

Cuestiones relacionadas