I have a JFrame that contains a custom JComponent that displays a grid with a fix amount of rows and columns. When the JFrame is resized, the spacing between lines is recalculated so that the grid increases in size while still keeping the same amount of elements. The issue comes when resizing to a height or width that is to large to fit n columns (or rows) but too small to fit n+1. Here's the correct view:
You can see the blue lines perfectly align with the black line on the right. If I increase the width of the window, I get the following problem:
The grid extends JComponent, and in its paintComponent I do the following:
// Get the size of the JFrame containing the Grid
Dimension df = getParent().getSize();
// Calculate spacing between vertical lines (20 = number of vertical lines)
int vert_spacing = (df.width - 2 * this.margin) / 20;
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin, this.margin, df.width - 2 * this.margin, df.height - 2 * this.margin);
// Draw vertical lines
for (int i = this.margin; i <= df.width - this.margin; i += vert_spacing) {
g.setColor(Color.blue);
g.drawLine(i, this.margin, i, df.height - this.margin);
}
A solution I thought of would be to "snap" to a good value after the JFrame is resized, but I haven't been able to get that to work and I'm not sure if it's the best solution. The issue is with the fact that drawLine takes ints as its values so the spacing between lines gets rounded up/down. Is there a workaround for this?
Thanks!
I think the problem is that you are painting the rectangle too large. You need to take into account that the rectangle size should be based on the vertical spacing * 20 and not the actual size of the parent window.
Maybe something like:
int vert_spacing = (df.width - 2 * this.margin) / 20;
int extraSpace = df.width - (vert_spacing * 20);
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin, this.margin, (df.width - extraSpace) - 2 * this.margin, df.height - 2 * this.margin);
Now of course the above solution will be skewed to the left so you may also want to center your grid in the space available. So in addition to using your margin as the X offset you would need to use half of the extra space:
int vert_spacing = (df.width - 2 * this.margin) / 20;
int extraSpace = df.width - (vert_spacing * 20);
int xOffset = extraSpace / 2;
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin + xOffset, this.margin, (df.width - extraSpace) - 2 * this.margin, df.height - 2 * this.margin);
Of course you would also need to use the xOffset when drawing the vertical lines.
You should work with floating coordinates and then round them just in order to get the integers required by the "draw" function:
// Calculate spacing between vertical lines (20 = number of vertical lines)
float vert_spacing = (float)(df.width - 2 * this.margin) / 20f;
// Draw vertical lines
for (int i=0; i<20; i++) {
int x = Math.round(this.margin + i*vert_spacing);
g.setColor(Color.blue);
g.drawLine(x, this.margin, x, df.height - this.margin);
}
Related
I am trying to draw 5 (for example) rectangles on canvas, using GC.drawRectangle(int x, int y, int width, int height);
After forth column rectangle should be drawn in next row as shown in the picture.Picture, layout for the rectangles drawn. I am not able to find some logic to draw rectangles as desired.
Here is what I was trying to do.
int col = (brushPanz-1) / 4;//gives column
int row = (brushPanz-1) % 4;//gives rows
for (int i = 0; i < brushPanz; i++) {
GC.drawRectangle((i * 172 + 5), col * 78 + 5, 500 / ratio, 220 / ratio);
}
Basically I want to use only one for loop to draw any number of rectangles. Someone, please help.
Without trying to debug your position offsets versus your size, you need (a) to compute a new row/col for each rect, (b) to use those computed values to position your rect and (c) to correctly compute row vs. column.
for (int i = 0; i < brushPanz; i++) {
int col = i % 4;//gives column
int row = i / 4;//gives rows
GC.drawRectangle((col * 172 + 5), row * 78 + 5, 500 / ratio, 220 / ratio);
}
i have created a 10x10 grid in the center of the screen in android, now i would like to give each square in the grid a coordinate. for example top left square in the grid would be 0 then 1, 2,3 and so on. But i dont know how to do this. i am trying to do this in a draw class which extends view. my code of what i am trying is below
public int coordinates(int posX, int posY){
int startX = (screenWidth / 2) - (rectSide / 2);
int startY = (screenHeight / 2) - (rectSide / 2);
//for(int i=0; i<=10000; i+=100){
xCoord = (startX + (posX*100));
yCoord = (startY + (posY*100));
}
You know you start at point 0,0 top left. So assuming you have equally spaces squares you can just do the screen height / 10 to get how far apart each square should be in the y direction. And then do the same for the x direction. Say your screen was 1000 pixels tall.
Then your grid at position (0,1) would be at (0,100) pixels. (0,2) would be (0,200) you are just multiplying the y coordinate by the height of each square in the grid.
Hello i'm currently working on a 2D Game Engine written entirely in java. Is there a way to centre a Graphics Object (g.drawString(x,y,z).
It would be preferably if this could be done through Graphics and the DefaultToolkit.
Thankyou very much :)
Simple mathematics. We have the object to be centered and the area where it should be centered.
Object width - w
Object height - h
Area width - aW
Area height - aH
//Follow center coordinates are coordinates where top left corner should be placed in order for the object to lie in center
centerWidth = (aW - W) /2
centerHeight = (aH - H) /2
As you can see, you MUST know the metrics of area you are placing your object on !
If that area is just the screen, then screen dimension can be used like this.
//Some dummy object metrics
int w = 30;
int h = 60;
//Now we find out the area metrics
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int aW = screenSize.width;
int aH = screenSize.height;
//Apply our common formula
int centerWidth = (aW - w) / 2;
int centerHeight = (aH - h) /2;
This works well for objects you know (their width and height).
Text centering
If you want to center text, you can use FontMetrics class, which allows you to measure size of text.
I need to draw random shapes on a grid such as lines squares etc. This part I'm able to do. My problem is the start and end point of the lines I'm drawing falls anywhere in a grid cell. I would like them to be only at intersection points. One cell in the grid is a 10x10 pixel grid. Do i have to write an algorithm to assign the pixel to its nearest intersection point on the grid or is there a easier way. I'm using a buffered image to draw the grid. Please Help. this is what i have so far
for (int i = 0; i < 61; i++) {
g2d.drawLine((imgDim.width + 2) / 40 * i, 0,
(imgDim.width + 2) / 40 * i, imgDim.height - 1);
g2d.drawLine(0, (imgDim.height + 2) / 60 * i,
imgDim.width - 1, (imgDim.height + 2) / 60 * i);
}
Thank you
How are you coming up with the random points? Making an adjustment there might be the easiest way. That is, just drop a 0 in the process you are using to come up with the points in the first place. Then when you are ready to draw it, add a 0 back.
Seriously? In order to make a random point (pixelX, pixelY) snap to the closest point of a grid.
int gridSize = 10;
int x = (pixelX + gridSize / 2) / gridSize * gridSize;
int y = (pixelY + gridSize / 2) / gridSize * gridSize;
I have a point array and a panel. getWidth() is based off the panel. Imagine cards in your hand, so HAND_CARD_WIDTH is pretty self explanatory. The purpose of this loop is to set the points evenly across the panel, which it does. However, it allow the cards to go out of the panel, which makes it look very bad. What I want to do is give a small empty margin on both sides of the panel no matter how many cards you have in your hand.
Here's the code
int iteration = 1;
int limiter = getWidth();
int slice = (limiter/(handsize+1));
while (points.size() < handsize) {
int x = slice*(iteration++);
x -= HAND_CARD_WIDTH/2;
points.add(new Point(x, y));
}
Basically I want the leftmost x to be at least 20 and the rightmost to be at most getWidth() - 20 - HAND_CARD_WIDTH. I also want the cards to be evenly spaced... I just can't think of the right equation (getting to this point was sadly a feat..).
Thanks, based on the responses (all 2 of them) heres what I went with:
if((int)points.get(0).getX() < margin){
int boost = Math.abs(margin - (int)points.get(0).getX());
slice = (boost*2)/handsize;
for(Point p : points){
p.x += boost;
boost -= slice;
}
}
Not sure if I understand your layout, but I think it is something like this:
|margin|space|card|space|card|space|margin|
or
|margin|space|card|space|margin|
So, the number of spaces is one more than number of cards and the total width is component width minus margins. componentWidth = numCards x cardWidth + (numCards + 1) x spaceWidth Now it is easy to calculate the space needed which is (componentWidth - numCards x cardWidth) / (numCards + 1) so the left position of a card is leftMargin + spaceWidth x cardNum + cardWidth x (cardNum - 1)
Care must be taken when the space is negative, then you instead must calculate how much the cards must overlap.
Try this:
final int MARGIN = 20;
int availableWidth = getWidth() - 2 * MARGIN - HAND_CARD_WIDTH;
int cardSpaceWidth = availableWidth / handsize;
for (int i = 0; i < handsize; i++) {
int x = MARGIN + ((i + 0.5) * cardSpaceWidth) - HAND_CARD_WIDTH / 2;
points.add(new Point(x, y));
}
So:
calculate the available width by subtracting the margins from total panel width
calculate the space for each card by dividing remaining space by number of cards
for each card, we count its leftmost point by taking the middle of card space and subtracting half the width of the card.
Mind you, with this solution cards still can overlap margins, if HAND_CARD_WIDTH is greater than available space for card.