Problems with newline in Graphics2D.drawString

JavaStringNewlineGraphics2d

Java Problem Overview


g2 is an instance of the class Graphics2D. I'd like to be able to draw multi-line text, but that requires a newline character. The following code renders in one line.

String newline = System.getProperty("line.separator");
g2.drawString("part1\r\n" + newline + "part2", x, y);

Java Solutions


Solution 1 - Java

The drawString method does not handle new-lines.

You'll have to split the string on new-line characters yourself and draw the lines one by one with a proper vertical offset:

void drawString(Graphics g, String text, int x, int y) {
    for (String line : text.split("\n"))
        g.drawString(line, x, y += g.getFontMetrics().getHeight());
}

Here is a complete example to give you the idea:

import java.awt.*;

public class TestComponent extends JPanel {

    private void drawString(Graphics g, String text, int x, int y) {
        for (String line : text.split("\n"))
            g.drawString(line, x, y += g.getFontMetrics().getHeight());
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawString(g, "hello\nworld", 20, 20);
        g.setFont(g.getFont().deriveFont(20f));
        drawString(g, "part1\npart2", 120, 120);
    }
    
    public static void main(String s[]) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new TestComponent());
        f.setSize(220, 220);
        f.setVisible(true);
    }
}

which gives the following result:

enter image description here

Solution 2 - Java

I just made a method to draw long text spliting automaticaly by giving the line width.

public static void drawStringMultiLine(Graphics2D g, String text, int lineWidth, int x, int y) {
	FontMetrics m = g.getFontMetrics();
	if(m.stringWidth(text) < lineWidth) {
		g.drawString(text, x, y);
	} else {
		String[] words = text.split(" ");
		String currentLine = words[0];
		for(int i = 1; i < words.length; i++) {
			if(m.stringWidth(currentLine+words[i]) < lineWidth) {
				currentLine += " "+words[i];
			} else {
				g.drawString(currentLine, x, y);
				y += m.getHeight();
				currentLine = words[i];
			}
		}
		if(currentLine.trim().length() > 0) {
			g.drawString(currentLine, x, y);
		}
	}
}

Solution 3 - Java

Here's a snippet I used to draw text in a JPanel with tab expansion and multiple lines:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;

public class Scratch {
    public static void main(String argv[]) {
        JFrame frame = new JFrame("FrameDemo");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel() {
            @Override
            public void paint(Graphics graphics) {
                graphics.drawRect(100, 100, 1, 1);
                String message =
                        "abc\tdef\n" +
                        "abcx\tdef\tghi\n" +
                        "xxxxxxxxdef\n" +
                        "xxxxxxxxxxxxxxxxghi\n";
                int x = 100;
                int y = 100;
                FontMetrics fontMetrics = graphics.getFontMetrics();
                Rectangle2D tabBounds = fontMetrics.getStringBounds(
                        "xxxxxxxx",
                        graphics);
                int tabWidth = (int)tabBounds.getWidth();
                String[] lines = message.split("\n");
                for (String line : lines) {
                    int xColumn = x;
                    String[] columns = line.split("\t");
                    for (String column : columns) {
                        if (xColumn != x) {
                            // Align to tab stop.
                            xColumn += tabWidth - (xColumn-x) % tabWidth;
                        }
                        Rectangle2D columnBounds = fontMetrics.getStringBounds(
                                column,
                                graphics);
                        graphics.drawString(
                                column,
                                xColumn,
                                y + fontMetrics.getAscent());
                        xColumn += columnBounds.getWidth();
                    }
                    y += fontMetrics.getHeight();
                }
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 200);
            }
        };
        frame.getContentPane().add(panel, BorderLayout.CENTER);

        frame.pack();

        frame.setVisible(true);    }
}

It really seemed like Utilities.drawTabbedText() was promising, but I couldn't figure out what it needed as input.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpkinskyView Question on Stackoverflow
Solution 1 - JavaaioobeView Answer on Stackoverflow
Solution 2 - JavaIvan De Sousa PazView Answer on Stackoverflow
Solution 3 - JavaDon KirkbyView Answer on Stackoverflow