Hi there. I'm learning Java and this is a sample applet in which I try some basic drawing operations. I hit some roadblocks and I'm hoping someone can point me in the right direction.

What I want to do here basically is make a rectangle with exactly 10 pixels of padding on each side, from the edges of the applet, and also put a piece of text so that the top edge of it is exactly in the top left corner of the rectangle.

Here's an image example of what I want.
Here's what I got with my sample program trying this.

As you can see, the text appears oriented by its baseline, instead of the top of the text, so it appears on top of the line instead of below.

Worse, though, the rectangle lines go on until past the edge of the applet. To fix this, offsets have to be applied: specifically, for some reason the width and height values returned from the applet seem to be 11 pixels too big for some reason, so 11 pixels need to be subtracted to get the proper position for the lower right corner of the rectangle.

See the code here (note that the font is different from in the images above):

import java.applet.*;
import java.awt.*;

public class applet_test extends Applet
{
	final int paddingX = 10, paddingY = 10;
	int width, height;
	//For some reason, an arbitrary offset appears to be necessary to get proper width and height.
	final int edgeOffset = 11;
	
	public void init()
	{
		setBackground(Color.lightGray);
		
		setSize(200, 200); //Size is 200x200 by default, but just in case; makes no difference.
		width = getSize().width - edgeOffset; //Offset necessary.
		height = getSize().height - edgeOffset; //Offset necessary.
	}
	
	public void paint(Graphics g)
	{
		g.setColor(Color.green);
		g.drawRect(paddingX, paddingY, width - paddingX, height - paddingY);
		
		Font font = new Font("Arial", Font.BOLD, 14);
		g.setFont(font);
		
		FontMetrics fontMetrics = g.getFontMetrics();
		int fontHeight = fontMetrics.getAscent() + fontMetrics.getDescent();
		
		g.setColor(Color.black);
		g.drawString("Top left rectangle corner", paddingX, paddingY + fontHeight);
		g.drawString("Further down", paddingX, paddingY + fontHeight + fontHeight);
		
		javax.swing.JOptionPane.showMessageDialog(null, "Ascent: " + Integer.toString(fontMetrics.getAscent()) + "\nDescent: " + Integer.toString(fontMetrics.getDescent()) + "\nLeading: " + Integer.toString(fontMetrics.getLeading()));
	}
}

Image result.

As you can see, I have to apply an arbitrary 11 pixel offset for reasons I'm not sure of. I've heard the problem is something to do with the rectangle's left_gap, right_gap, etc., which are added as offsets and mess things up.

Also, the font doesn't seem to be cooperating. Since fonts are positioned by the baseline, I'm trying to position it at its normal position + the font height, but the ascent seems unnaturally large. In the Arial 14 bold font used in the code, for example, the ascent is 13, descent is 3, and leading only 1. From the documentation, it seems like the ascent should extend only from the baseline to the top of most characters. Here it seems to include an entire line break as well. Shouldn't the leading be for that?

So those are my two problems: trying to get rid of the arbitrary 11 pixel offset, and getting the proper font height, from baseline to top of character only, so I can position the text by its topline, essentially.

Any help would be much appreciated.

Well, firstly you dont need the arbitrary 11 or whatever.
You just need to calculate both ends. If you subtract paddingY(paddingX) from width(length), you only handle one end. So you should subtract paddingY*2 (paddingX*2) to make the paddings equal on each side.

For your second problem, if you use getHeight() - getDescent() for font height, you will achieve your goal.

import java.applet.*;
import java.awt.*;

public class applet_test extends Applet {
	final int paddingX = 10, paddingY = 10;
	int width, height;

	public void init() {
		setBackground(Color.lightGray);

		setSize(200, 200); // Size is 200x200 by default, but just in case;
							// makes no difference.
		width = getSize().width;
		height = getSize().height;
	}

	public void paint(Graphics g) {
		g.setColor(Color.green);
		g.drawRect(paddingX, paddingY, width - (paddingX * 2), height
				- (paddingY * 2));

		Font font = new Font("Arial", Font.BOLD, 14);
		g.setFont(font);

		FontMetrics fontMetrics = g.getFontMetrics();
		int fontHeight = fontMetrics.getHeight() - fontMetrics.getDescent();

		g.setColor(Color.black);
		g.drawString("Top left rectangle corner", paddingX, paddingY + fontHeight);
		g.drawString("Further down", paddingX, paddingY + (fontHeight * 2));

		javax.swing.JOptionPane.showMessageDialog(null, "Ascent: "
				+ Integer.toString(fontMetrics.getAscent()) + "\nDescent: "
				+ Integer.toString(fontMetrics.getDescent()) + "\nLeading: "
				+ Integer.toString(fontMetrics.getLeading()));
	}
}

Thanks very much for the response.

1. Well, congratulations to me for completely misreading the documentation. Somehow I overlooked the fact that the 3rd and 4th arguments to drawRect are called "width" and "height" not "x2" and "y2" and acted on assumption, even after rereading the function's documentation several times. Pretty embarrassing. Then I got caught off on the left_gap etc. red herring and assumed it was some extraneous GUI thing. Sorry for even bothering you with that.

2. Anyway, getHeight - getDescent doesn't really achieve my goal, not exactly anyway. The unnaturally large size of getAscent still causes there to be a slight gap, so that the text appears slightly below the desired position (and after all, getHeight is just ascent + descent + leading). I'm not willing to be too fussy about it, but I still find it a little strange that ascent is so large and leading so small.

You should just play with different things and find the solution you want.

When you say that, I just subtracted in this way : fontMetrics.getHeight() - fontMetrics.getDescent()*2 , I think this meets your requirement better.

import java.applet.*;
import java.awt.*;

public class applet_test extends Applet {
	final int paddingX = 10, paddingY = 10;
	int width, height;

	public void init() {
		setBackground(Color.lightGray);

		setSize(200, 200); // Size is 200x200 by default, but just in case;
							// makes no difference.
		width = getSize().width;
		height = getSize().height;
	}

	public void paint(Graphics g) {
		g.setColor(Color.green);
		g.drawRect(paddingX, paddingY, width - (paddingX * 2), height
				- (paddingY * 2));

		Font font = new Font("Arial", Font.BOLD, 14);
		g.setFont(font);

		FontMetrics fontMetrics = g.getFontMetrics();
		int fontHeight = fontMetrics.getHeight() - fontMetrics.getDescent()*2;

		g.setColor(Color.black);
		g.drawString("Top left rectangle corner", paddingX, paddingY + fontHeight);
		g.drawString("Further down", paddingX, paddingY + (fontHeight * 2));

	}
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.