Text won't align right.

I’ve been trying to make better fonts, using java, so I can apply it to my game later. But for some reason, I can’t draw more then 2 fonts.

Here’s the code


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.*;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class FontTest extends JPanel {

    public MyFont f;
    public MyFont f2;

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        f = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "2/4");
        f.drawText();
        f2 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "3/4");
        f2.drawText();
    }

    public class MyFont {

        public int centerX;
        public int centerY;
        public Shape text;
        public Graphics2D g;
        public String kind;
        public int x;
        public int y;
        public int s;
        public int str;
        public Color oc;
        public Color ic;
        public String word;
        public int w;
        public int h;

        public MyFont(Graphics2D g2d, String font, int x2, int y2, int s2, int stroke, Color outColor, Color inColor, String word2) {
            g = g2d;
            kind = font;
            x = x2;
            y = y2;
            s = s2;
            str = stroke;
            oc = outColor;
            ic = inColor;
            word = word2;
        }

        public void drawText() {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            ge.getAllFonts();
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            FontRenderContext frc = g.getFontRenderContext();
            Font font = new Font(kind, Font.PLAIN, s);
            TextLayout tl = new TextLayout(word, font, frc);
            AffineTransform transform = new AffineTransform();
            text = tl.getOutline(null);
            w = text.getBounds().width;
            h = text.getBounds().height;
            centerX = (w / 2);
            centerY = (h / 2);
            transform.translate(x - centerX, y + centerY);
            g.transform(transform);
            g.setStroke(new BasicStroke(str, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g.setColor(oc);
            g.draw(text);
            g.setColor(ic);
            g.fill(text);
            g.clip(text);
        }

        public int getWidth() {
            return w;
        }

        public int getHeight() {
            return h;
        }

        public int centerX() {
            return centerX();
        }

        public int centerY() {
            return centerY();
        }
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new FontTest());
        f.setSize(400, 400);
        f.setVisible(true);
    }
}


That’s because you call “g.clip(text)” on the last line of MyFont.drawText(). The clip(Shape) method intersects the current clip with the shape, causing all rendering outside of the resulting shape to be ignored. I ran your code, removed that line, and both strings rendered :wink:

Thanks, I didn’t know that line would do that.XD

For some reason, my texts get messed up, even though I put in the same coordinates for each text.

Here is the new code


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.*;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class FontTest extends JPanel {

    public MyFont f;
    public MyFont f2;
    public MyFont f3;
    public MyFont f4;

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        f = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "2/4");
        f.drawText();
        f2 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "3/4");
        f2.drawText();
        f3 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "9999");
        f3.drawText();
        f4 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "9989");
        f4.drawText();
    }

    public class MyFont {

        public int centerX;
        public int centerY;
        public Shape text;
        public Graphics2D g;
        public String kind;
        public int x;
        public int y;
        public int s;
        public int str;
        public Color oc;
        public Color ic;
        public String word;
        public int w;
        public int h;
        AffineTransform transform = new AffineTransform();

        public MyFont(Graphics2D g2d, String font, int x2, int y2, int s2, int stroke, Color outColor, Color inColor, String word2) {
            g = g2d;
            kind = font;
            x = x2;
            y = y2;
            s = s2;
            str = stroke;
            oc = outColor;
            ic = inColor;
            word = word2;

        }

        public void drawText() {
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            ge.getAllFonts();
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            FontRenderContext frc = g.getFontRenderContext();
            Font font = new Font(kind, Font.PLAIN, s);
            TextLayout tl = new TextLayout(word, font, frc);
            text = tl.getOutline(null);
            w = text.getBounds().width;
            h = text.getBounds().height;
            centerX = (w / 2);
            centerY = (y / 2);
            transform.translate(x - centerX, y - centerY);
            g.transform(transform);
            g.setStroke(new BasicStroke(str, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL));
            g.setColor(oc);
            g.draw(text);
            g.setColor(ic);
            g.fill(text);
        }

        public int getWidth() {
            return w;
        }

        public int getHeight() {
            return h;
        }

        public int getCenterX() {
            return centerX;
        }

        public int getCenterY() {
            return centerY;
        }
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new FontTest());
        f.setSize(400, 700);
        f.setVisible(true);
    }
}

what do you mean by it wont align? you gave same point exactly (same X, same Y) to these string. without run it, I guess they overwrite each other.

No that is not the reason, I noticed that peculiar behavior when I ran it. You have just experienced a common pitfall of OOP. You are passing the same Graphics object to both MyFont objects. In MyFont #1, you set the Transform to translate (x-centerX,y-centerY). Then you keep that transform and re-translate in the next MyFont object, causing each MyFont to be offset by the translation of all previous MyFonts.
You have 2 options here:
-Either reset the old transform after drawText() returns like this:


AffineTransform old = g.getTransform();
//drawing code
g.setTransform(old);

-Use Graphics.create() for each MyFont to get a new instance of Graphics that is an exact replica of the original.

I personally recommend the second option since it lets you do whatever you want to the Graphics object without affecting the others.

Thanks for the reply, but for some reason, when i did it like this


@Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        f = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "2/4");
        f.drawText();
        g2d.create();
        f2 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "3/4");
        f2.drawText();
        g2d.create();
        f3 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "9999");
        f3.drawText();
        g2d.create();
        f4 = new MyFont(g2d, "DejaVu Sans Mono", 100, 100, 36, 5, Color.GRAY, Color.WHITE, "9989");
        f4.drawText();
        g2d.create();
    }

The Graphics still wouldn’t align correctly(i want them to overlap, so that I can tell if the align correctly).
I tried many alternatives, but they just get the same result, or worse.
I’m I doing something wrong?

create() returns a new instance, it doesn’t affect the original one. They will both render to the same destination, but they are two different object references.

However, remember that create() returns an exact replica of the original, so any transformations that you did will be copied over. Try calling create() inside the constructor:


public MyFont(....) {
    this.g = (Graphics2D)g2d.create();
    ...
}

Thanks that worked. :slight_smile:

Glad to help :smiley: