2008-10-27 7 views
11

Mon programme afin public void paint(Graphics g, int x, int y); remplace tirer quelques piqûres en utilisant g.drawString(someString, x+10, y+30);Comment produire une chaîne sur plusieurs lignes en utilisant Graphics

Maintenant someString peut être assez long et donc, il ne peut tenir sur une ligne.

Quelle est la meilleure façon d'écrire le texte sur plusieurs lignes.
Par exemple, dans un rectangle (x1, y1, x2, y2)?

Répondre

9

Merci à l'indice Epaga et quelques exemples sur le Net (pas si évident à trouver! J'ai utilisé principalement Break a Line for text layout), je pourrais faire un composant pour afficher le texte enveloppé. C'est incomplet, mais au moins cela montre l'effet recherché.

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

Juste pour le plaisir, je l'ai fait convenable un cercle (hélas, aucune justification, il semble):

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

Je ne suis pas sûr de calcul dx, cependant.

3

java.awt.font.TextLayout peut vous être utile. Voici un extrait de leur code d'exemple:

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

Sinon, vous pouvez toujours utiliser un élément de texte Swing pour faire le travail pour vous, il suffit de passer dans les graphiques que vous voulez à peindre en.

+0

Je l'ai déjà eu. Mon problème est, je ne veux pas un rectangle autour du texte, mais le texte à l'intérieur d'un rectangle donné. – Burkhard

+0

Notez que le constructeur de TextLayout, non documenté, lève une exception si la chaîne que vous passez est vide. –

+1

Utilisez \t Forme labelShape = textLayout1.getOutline (null); puis g2d.fill (labelShape); ils devraient éliminer la frontière – mk7

1

Créez de manière incrémentielle votre chaîne, un mot à la fois, en utilisant la méthode d'Epaga pour trouver la longueur de votre chaîne. Une fois que la longueur est plus longue que votre rectangle, supprimez le dernier mot et imprimez. Répétez jusqu'à ce que vous manquiez de mots.

Cela ressemble à un mauvais algorithme, mais pour chaque ligne, c'est vraiment O (screenWidth/averageCharacterWidth) => O (1).

Encore, utilisez un StringBuffer pour construire votre chaîne!

+1

Cela ne va pas avoir une complexité de temps de O (1); O (n), peut-être, comme vous devez (au moins) ajouter un mot (c'est-à-dire ajouter un nombre de caractères dans le StringBuilder.append) jusqu'à ce que tous les caractères aient été utilisés. – jamesh

+0

Je semble être mauvais à m'exprimer correctement ... Je voulais dire que chaque ligne est O (1). Vous pouvez y lancer 1000 mots, mais pour chaque ligne, il va cesser d'ajouter des mots au bord de l'écran. Dans l'ensemble, oui, O (n). –

+0

Cela ne fonctionne que si vous supposez que la chaîne sera à 2 lignes maximum, alors que cela ne fonctionnera pas. –

0

Vous pouvez utiliser un JLabel et intégrer le texte au format html.

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

Votre code HTML est supprimé. Je suppose que le premier littéral de chaîne est et le second est
. –

+1

Cela ne va-t-il pas à l'encontre du but si vous devez ajouter vos propres sauts de ligne? –

1

eu quelques problèmes moi-même est ma solution:

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

espoir qui aide .... simple mais cela fonctionne.

Questions connexes