AffineTransform seeming to ignore component bounds - java

I have the following:
public class ParametricEQView extends JPanel implements PluginView {
private static final int BAND_WIDTH = 3;
private static final int THROW_HEIGHT = 64;
private static final int WIDTH = 128*BAND_WIDTH + 2*MARGIN;
private static final int HEIGHT = 2*THROW_HEIGHT + 2*MARGIN;
private static final int MID_HEIGHT = THROW_HEIGHT + MARGIN;
private final ParametricEQ _peq;
public ParametricEQView(ParametricEQ peq) {
super();
_peq = peq;
SwingUtils.freezeSize(this, WIDTH, HEIGHT);
setToolTipText("Parametric Equalizer");
}
#Override
public void paint(Graphics g) {
final Graphics2D g2d = (Graphics2D) g;
final int max = findMax();
g.setColor(BACKGROUND);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(DATA);
final double scalingFactor = -((double) THROW_HEIGHT) / max;
final double[] fineLevels = _peq.getFineLevels();
int x = MARGIN;
int h;
final int[] xPoints = new int[128];
final int[] yPoints = new int[128];
for (int i = 0; i < 128; ++i) {
h = (int) (fineLevels[i] * scalingFactor);
xPoints[i] = x;
yPoints[i] = MID_HEIGHT + h;
x += BAND_WIDTH;
}
g.drawPolyline(xPoints, yPoints, 128);
g.setColor(AXES);
g.drawLine(MARGIN, MARGIN, MARGIN, HEIGHT-MARGIN);
g.drawLine(MARGIN, MID_HEIGHT, WIDTH-MARGIN, MID_HEIGHT);
g.setFont(AXIS_FONT);
final FontMetrics metrics = g.getFontMetrics();
int width = (int) metrics.getStringBounds(AXIS_LABEL_INPUT_MIDINUM, g).getWidth();
g.drawString(AXIS_LABEL_INPUT_MIDINUM, WIDTH-MARGIN-width, HEIGHT-3);
final AffineTransform atx = new AffineTransform();
atx.setToRotation(-Math.PI/2, 0, HEIGHT);
g2d.setTransform(atx);
final String topLabel = "+" + max;
width = (int) metrics.getStringBounds(topLabel, g).getWidth();
g2d.drawString(topLabel, HEIGHT-MARGIN-width, HEIGHT+10);
width = (int) metrics.getStringBounds(AXIS_LABEL_OUTPUT_VELOCITY, g).getWidth();
g2d.drawString(AXIS_LABEL_OUTPUT_VELOCITY, MID_HEIGHT-(width/2), HEIGHT+10);
g2d.drawString("-" + max, MARGIN, HEIGHT+10);
}
private int findMax() {
int max = 3;
for (int i = 0; i < 128; ++i)
max = Math.max(max, (int) Math.ceil(Math.abs(_peq.getFineLevels()[i])));
return max;
}
}
This is what it looks like:
The ParametricEQView is the component with the white background filling most of the window. In this image its coordinates are (0,0) in the containing frame and everything is great. However, if I resize the window so that the ParametricEQView moves over a bit (it has a fixed size and is set to be centered in its available space), the rotated text stays relative to the (0,0) of the frame instead of the component:
Everything else draws relative to the panel, it's just the rotated text that doesn't. What am I doing wrong?

When you call g2d.setTransform(atx); you override the transform currently set in the Graphics object, i.e. the translation between the panel and its parent frame. That's why the text is drawn in the frame referential, and not in the panel referential.
The correct code would be to get the current transform and modify it or directly call Graphics2D.rotate(double).

1) For custom paintings you need to override protected void paintComponent(Graphics g) instead of public void paint(Graphics g). Read more about customPaintings.
2)Seems you have your problem, because you do something like next for creation of GUI:
JFrame frame = new JFrame();
JPanel p = new JPanel();
ParametricEQView view = new ParametricEQView();
view.setPreferredSize(new Dimension(200,200));
p.add(view);
frame.add(p);
in that case ParametricEQView doesn't resize as you want, because JPanel use FlowLayout as default.
You need to use another LayoutManager for your panel, for example BorderLayout.
Try something like next:
JFrame frame = new JFrame();
ParametricEQView view = new ParametricEQView();
frame.add(view);
or
JPanel panel = new JPanel(new BorderLayout());
panel.add(view,BorderLayout.CENTER);
frame.add(panel);
in that case your ParametricEQView panel will be painting in proper way.

Related

How to add multiple rectangles to a jframe(trying to code 2048 in an easy way)

I made the game already and wanted to make my GUI look better with rectangles not with jlabels and now I´ve come to realize that only the last rectangle that is drawn is shown on the GUI
I already tried it with different layouts
my GUI class:
public class GUI_N
{
private Spiel spiel;
private KeyEvent e;
private String beste;
private int beste1;
private DrawingComponent[][] feld;
GUI_N(){
feld = new DrawingComponent[4][4];
spiel = new Spiel();
beste1 = 0;
beste = "Highscore: "+beste1;
JFrame g=new JFrame("2048 - Main");
g.setSize(500,500);
g.setFocusable(true); //wichtig für KeyListener
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int i = 0;
int j = 0;
int h = 0;
int l = 0;
while(i<4)
{
while(j<4)
{
if(i==0){
h = 50;
}else if(i==1){
h = 100;
}else if(i==2){
h = 150;
}else if(i==3){
h = 200;
}
if(j==0){
l = 50;
}else if(j==1){
l = 100;
}else if(j==2){
l = 150;
}else if(j==3){
l = 200;
}
feld[i][j] = new DrawingComponent(l,h,50,50);
feld[i][j].setBounds(l,h,50,50);
j++;
}
j=0;
i++;
}
i = 0;
j = 0;
while(i<4)
{
while(j<4)
{
g.add(feld[i][j]);
j++;
}
j=0;
i++;
}
//g.getContentPane().setBackground(new Color(20, 40, 50));
g.setVisible(true);
}
public static void main(String[] args) {
new GUI_N();
}
}
my rectangle class:
public class DrawingComponent extends JComponent
{
private Graphics2D g2;
private int wert;
private int x;
private int y;
private int w;
private int h;
public DrawingComponent(int px,int py,int pw,int ph)
{
x=px;
y=py;
w=pw;
h=ph;
}
public void paintComponent(Graphics g)
{
g2 = (Graphics2D) g;
Rectangle rect1 = new Rectangle(x,y,w,h);
g2.setColor(Color.RED);
g2.fill(rect1);
}
public void setWert(int x)
{
wert = x;
}
public int getWert()
{
return wert;
}
}
as I said only the last drawn rectangle is shown.
How do I achieve this?
Right now you're adding the rectangles directly to your frame. You should have a JPanel layer in between, to which you can give a LayoutManager (GridLayout would be a good one to look at) to arrange all your rectangles.
So you would have something like this:
JFrame g = new JFrame("2048 - Main");
// GridLayout (on next line) takes number of rows and columns
JPanel panel = new JPanel(new GridLayout(4, 4));
// ... add all the rectangles to the panel here
g.add(panel);
And then you would add your rectangles to the panel, not the frame. As you add them, they will automatically go into place in the grid.
panel.add(feld[i][j]);
Also, if you use GridLayout, it will resize and fit the components to the grid dynamically, so it may save you some code as well, since you wouldn't need to hardcode their sizes in the GUI class.

Painting an arbitrary collection of points quickly

I am writing a darts application, and have implemented a Dartboard which is painted as a BufferedImage.
When rendering the dartboard, I first iterate over the co-ordinates of the BufferedImage and calculate the 'segment' that it resides in. I wrap this up into a DartboardSegment, which is basically just a collection of points with a small amount of extra structure (what number on the board it corresponds to, etc).
Currently, to actually render the dartboard I paint each point individually, like the following:
for (Point pt : allPoints)
{
DartboardSegment segment = getSegmentForPoint(pt);
Color colour = DartboardUtil.getColourForSegment(segment);
int rgb = colour.getRGB();
int x = (int)pt.getX();
int y = (int)pt.getY();
dartboardImage.setRGB(x, y, rgb);
}
Obviously this takes some time. It's not an intolerable amount (~2-3s to paint a 500x500 area), but I'd like to eliminate this 'lag' if I can. In other areas of my application I have encountered alternate methods (such as Graphics.fillRect()) which are much faster.
I've seen that there is a fillPolgyon() method on the Graphics class, however I don't think I can easily convert my segments into polygons because their shapes vary (e.g. the shape of a triple, a circle for the bullseye...). Is there a faster way in java to paint an arbitrary array of Points at once, rather than looping through and painting individually?
The code that I want to write is something like:
for (DartboardSegment segment : allSegments)
{
Color colour = DartboardUtil.getColourForSegment(segment);
Polgyon poly = segment.toPolygon();
Graphics gfx = dartboardImage.getGraphics();
gfx.setColor(colour);
gfx.fillPolygon(poly);
}
I don't think I can easily convert my segments into polygons because their shapes vary (e.g. the shape of a triple, a circle for the bullseye...)
Here is something that may give you some ideas.
You can create Shape objects to represent each area of the dartboard:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import java.awt.geom.*;
public class Dartboard extends JPanel
{
private ArrayList<DartboardSegment> segments = new ArrayList<DartboardSegment>();
private int size = 500;
private int radius = size / 2;
private int border = 25;
private int doubleSize = size - (2 * border);
private int tripleSize = size / 2;
private int thickness = 10;
public Dartboard()
{
createSegmentWedges();
int innerRadius = size - (2 * border);
Shape outer = new Ellipse2D.Double(0, 0, size, size);
Shape inner = new Ellipse2D.Double(border, border, innerRadius, innerRadius);
Area circle = new Area( outer );
circle.subtract( new Area(inner) );
segments.add( new DartboardSegment(circle, Color.BLACK) );
createBullsEye();
}
private void createSegmentWedges()
{
int angle = -99;
for (int i = 0; i < 20; i++)
{
// Create the wedge shape
GeneralPath path = new GeneralPath();
path.moveTo(250, 250);
double radians1 = Math.toRadians( angle );
double x1 = Math.cos(radians1) * radius;
double y1 = Math.sin(radians1) * radius;
path.lineTo(x1 + 250, y1 + 250);
angle += 18;
double radians2 = Math.toRadians( angle );
double x2 = Math.cos(radians2) * radius;
double y2 = Math.sin(radians2) * radius;
path.lineTo(x2 + 250, y2 + 250);
path.closePath();
Color wedgeColor = (i % 2 == 0) ? Color.BLACK : Color.WHITE;
segments.add( new DartboardSegment(path, wedgeColor) );
// Create the double/triple shapes
Color color = (i % 2 == 0) ? Color.RED : Color.GREEN;
createShape(doubleSize, path, color);
createShape(tripleSize, path, color);
}
}
private void createShape(int outerSize, GeneralPath path, Color color)
{
int outerOffset = (size - outerSize) / 2;
int innerSize = outerSize - (2 * thickness);
int innerOffset = (size - innerSize) / 2;
Shape outer = new Ellipse2D.Double(outerOffset, outerOffset, outerSize, outerSize);
Shape inner = new Ellipse2D.Double(innerOffset, innerOffset, innerSize, innerSize);
Area circle = new Area( outer );
circle.subtract( new Area(inner) );
circle.intersect( new Area(path) );
segments.add( new DartboardSegment(circle, color) );
}
private void createBullsEye()
{
int radius1 = 40;
int offset1 = (size - radius1) / 2;
Ellipse2D.Double bullsEye1 = new Ellipse2D.Double(offset1, offset1, radius1, radius1);
segments.add( new DartboardSegment(bullsEye1, Color.GREEN) );
int radius2 = 20;
int offset2 = (size - radius2) / 2;
Ellipse2D.Double bullsEye2 = new Ellipse2D.Double(offset2, offset2, radius2, radius2);
segments.add( new DartboardSegment(bullsEye2, Color.RED) );
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
for (DartboardSegment segment: segments)
{
g2d.setColor( segment.getColor() );
g2d.fill( segment.getShape() );
}
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(500, 500);
}
class DartboardSegment
{
private Shape shape;
private Color color;
public DartboardSegment(Shape shape, Color color)
{
this.shape = shape;
this.color = color;
}
public Shape getShape()
{
return shape;
}
public Color getColor()
{
return color;
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("DartBoard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Dartboard());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
After a bit more digging, I think one solution to this is to do the following. It's not the neatest, but I think it will work:
int i = 0;
for (int y=0; y<height; y++)
{
for (int x=0; x<width; x++)
{
Point pt = new Point(x, y);
DartboardSegment segment = getSegmentForPoint(pt);
Color colour = DartboardUtil.getColourForSegment(segment);
pixels[i] = colorToUse.getRGB();
i++;
}
}
dartboardImage.setRGB(0, 0, width, height, pixels, 0, width);
I am open to better suggestions, however!

JPanel Window not scaling when resize the main frame

I was working on my code to draw a number of lines that the user inputted and the first end-point is centered at the y-coordinate while the second end-points are apart from each other by height/(number of lines the user entered). I verified my code and everything seems to be working fine except the fact that the JPanel does not scale as it should, corresponding to the size of the main frame. Can anyone please give me an advice?
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Scanner;
public class DrawPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
Scanner input = new Scanner(System.in); //create object input from Scanner class
System.out.println("Enter number of lines + 1 to draw: "); //ask for user input
int stepSize = input.nextInt(); //initialize stepSize to take user input
int endX = width; //starting position of second pt for x
int endY = height; //starting position of second pt for y
for(int i = 0; i < stepSize + 1; i++)
{
int verticalStep = height / stepSize; //separate y-coordinate second endpts apart
int midPoint = height / 2;
g.drawLine(0, midPoint, endX, endY);
endY = endY - verticalStep;
}
}
}
import javax.swing.JFrame;
public class DrawPanelTest
{
public static void main(String[] args)
{
DrawPanel panel = new DrawPanel();
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(panel);
window.setSize(500, 500); //set size of the application
window.setVisible(true); //display the application
}
}
The default layout of JPanel is FlowLayout, which uses the preferred size of the enclosed components. Instead, use GridLayout, for example. It will grow and shrink as the frame is resized. Instead of setSize(), give your panel an initial preferred size as shown here.
Thank you for your feedbacks guys. I have figured out how to do it as I should not use Scanner class to ask for the user input. Below is my edited code for this assignment:
public class DrawPanel extends JPanel
{
private int userChoice;
public DrawPanel(int choice)
{
userChoice = choice;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);//call paintComponent to ensure the window displays correctly
int width = getWidth(); //total width
int height = getHeight();//total height
int endX = width; //starting position of second pt for x
int endY = height; //starting position of second pt for y
//increment from 0 to the user inputted stepSize to draw lines
for(int i = 1; i <= userChoice + 1; i++)
{
int verticalStep = height / userChoice; //separate y-coordinate second endpts apart
int midPoint = height / 2; //center the starting position in the y-axis of first endpoint
g.drawLine(0, midPoint, endX, endY); //draw lines
endY = endY - verticalStep; //move the second endpoints either up or down
}
}
}
public class DrawPanelTest
{
public static void main(String[] args)
{
int choice = Integer.parseInt(args [0]);
DrawPanel panel = new DrawPanel(choice);//create a panel that contains the lines
JFrame window = new JFrame(); //create a frame to hold the panel
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //set frame to exit when closed
window.add(panel); //add panel to the frame
window.setSize(500, 500);//set size for the frame
window.setVisible(true); //display the frame
}

How can I draw several rectangles in a row programmatically?

I want to put several rectangle i a row. But because I'm new to Android and specially to Bitmap, Canvas and so on, I need some help.
It should look like this, only with rectangles:
I have created one rectangle with this code:
Paint paint = new Paint();
paint.setColor(Color.parseColor("#CD5C5C"));
Bitmap bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bg);
canvas.drawRect(50, 80, 200, 200, paint);
RelativeLayout ll = (RelativeLayout) findViewById(R.id.rect);
ImageView iV = new ImageView(this);
iV.setImageBitmap(bg);
ll.addView(iV);
But now I dont know how to create more rectangles with different colors in a row.
I'm really new and sorry for that maybe stupid question but I need help for it.
Can anybody guide me how to do this in the best way?
The key here are these lines:
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(50, 80, 200, 200, paint);
They set the colour and draw a rectangle. You can now repeat these lines to get 2 rectangles:
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(50, 80, 200, 200, paint);
paint.setColor(Color.parseColor("#DDDDDD"));
canvas.drawRect(210, 80, 360, 200, paint);
Note that I have changed the colour and co-ordinates a little bit. You could continue doing this several times to get all of your rectangles drawn.
Better still use a variable for the x and y coordinates, and use a loop:
int left = 50; // initial start position of rectangles (50 pixels from left)
int top = 50; // 50 pixels from the top
int width = 150;
int height = 150;
for (int row = 0; row < 2; row++) { // draw 2 rows
for(int col = 0; col < 4; col++) { // draw 4 columns
paint.setColor(Color.parseColor("#CD5C5C"));
canvas.drawRect(left, top, left+width, top+height, paint);
left = (left + width + 10); // set new left co-ordinate + 10 pixel gap
// Do other things here
// i.e. change colour
}
top = top + height + 10; // move to new row by changing the top co-ordinate
}
Hope that helps.
This should do it. I tried to self-document my code as mush as possible. This is very dynamic i.e. you can adjust the height, width, xPad, yPad, etc. and the window will compensate.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class RectanglesPanel extends JPanel {
public static final int[] COLORS = new int[] {
0xFFFFFF, 0xF67457, 0xFFC238, 0xEFEF38,
0xBCCACA, 0x75D1E0, 0x84E0C2, 0xC2E749
};
private static Random rand = new Random();
private int width = 80;
private int height = 50;
private int rows = 2;
private int cols = 4;
private int xPad = 20;
private int yPad = 30;
private float strokeWidth = 2.0f;
int windowWidth = calculateOffset(width, cols, xPad);
int windowHeight = calculateOffset(height, rows, yPad);
public RectanglesPanel() {
setPreferredSize(new Dimension(windowWidth, windowHeight));
}
private int calculateOffset(int whole, int partitions, int padding) {
return (whole * partitions) + (padding * (partitions + 1));
}
#Override
public void paintComponent(Graphics g) {
Stroke stroke = new BasicStroke(strokeWidth,
BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
((Graphics2D)g).setStroke(stroke);
// Fill in background.
g.setColor(new Color(0xF6F6F6));
g.fillRect(0, 0, windowWidth, windowHeight);
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
int x = calculateOffset(width, col, xPad);
int y = calculateOffset(height, row, yPad);
int color = (row * cols + col) % COLORS.length;
// Fill in rectangle.
g.setColor(new Color(COLORS[color]));
g.fillRect(x, y, width, height);
// Stroke the border of the rectangle.
g.setColor(new Color(0xE7E7E7));
g.drawRect(x, y, width, height);
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new RectanglesPanel();
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
use for loop keeping the y coordinates constant
for(i=0;i<=200;i=i+40)
{
canvas.drawRect(i,0,i+30,100);
}
for next row increase y coordinate by your require amount and repeat the same or use nested for loops
you can set color by
myPaint.setColor(color.black);
myPaint.setStyle(Style.FILL);
canvas.drawRect(0,0,100,100, myPaint);

Creating a Checkers Board in Java

I'm begining a little project to create a simple checkers game. However it's been a long time since I've used the java GUI tools. The goal of the code at this point is to draw the initial board (red pieces at top, black at bottom). However all I get when I run the code is a blank frame. I'm also a little uncertain if my circle drawing code will do what I want (ie create solid red or black circles inside certain squares) Here is the code. Thanks in advance for any help/suggestions
EDIT: I should probably alternate drawing blue and gray squares or else the thing will probably just be a giant blue blob, however I'll settle for a giant blue blob at this point :p
import javax.swing.*;
import java.awt.*;
public class CheckersServer
{
public static class Board
{
private JFrame frame = new JFrame();
private JPanel backBoard = new JPanel();
Board()
{
frame.setSize(905,905);
backBoard.setSize(900,900);
frame.setTitle("Checkers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
backBoard.setVisible(true);
boardSquare bs;
String type = null;
//Filling in Red Side
for (int i = 0; i <=1; i++)
{
for(int j = 0; j < 9; j++)
{
if(j % 2 == 0)
{
type = "Red";
}
else
{
type = "Blank";
}
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
//Filling in empty middle
type = "Blank";
for (int i = 2; i < 7; i++)
{
for(int j = 0; j < 9; j++)
{
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
//Filling in Black side
for (int i = 7; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
if(j % 2 != 0)
{
type = "Black";
}
else
{
type = "Blank";
}
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
backBoard.repaint();
frame.add(backBoard);
frame.repaint();
}
private class boardSquare extends JComponent
{
private int x; //x position of the rectangle measured from top left corner
private int y; //y position of the rectangle measured from top left corner
private boolean isBlack = false;
private boolean isRed = false;
public boardSquare(int p, int q, String type)
{
x = p;
y = q;
if (type.equals("Black"))
{
isBlack = true;
isRed = false;
}
else if (type.equals("Red"))
{
isRed = true;
isBlack = false;
}
else if (type.equals("Blank"))
{
isBlack = false;
isRed = false;
}
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(x,y,100,100);
g2.draw(box);
g2.setPaint(Color.BLUE);
g2.fill(box);
if(isBlack)
{
g2.fillOval(x, y,100 ,100 );
g2.setColor(Color.black);
g2.drawOval(x, y, 100, 100);
}
else if(isRed)
{
g2.fillOval(x, y,100 ,100 );
g2.setColor(Color.red);
g2.drawOval(x, y, 100, 100);
}
}
}
}
public static void main(String[] args)
{
Board game = new Board();
}
}
You have several issues.
Java UI is layout-based, which means that when you add a component to a parent, the parent's layout determines where the child component will be placed. You don't have any code to set up the layout, and so your application is using the defaults (FlowLayout is the default, and this may work in your case, as long as your JFrame and children are the appropriate size).
The bigger problems are in your boardSquare class. By default, JPanels have a dimension of 10x10. You aren't specifying the size, and so all your squares are 10x10. You need to tell the squares how big they are. You can do this in the boardSquare constructor:
setPreferredSize(new Dimension(100, 100));
Finally, in your drawing code, you are doing an offset of x,y when drawing the squares and circles. This is an offset from the top-left corner of the component. Your components (after setting the size) will be 100x100 pixels. But if your x,y are greater than these values, you will be drawing outside of the bounds of the component. Instead, these values should be set to 0,0 because that is the top-left corner of the component you are drawing in.
By just setting the preferred size of the squares and setting x,y to 0, I was able to get the squares drawing in the frame, though it wasn't pretty. You will need to work on setting the correct layout before it will be laid out correctly.
Here are some hints:
Your BoardSquares have dimension 0x0. Not a good size for something you want to be visible to the user.
To help visualize what's going on, cause each BoardSquare to be 100x100 pixels in size, and give them a border. Now you can see where they are showing up in your GUI. Your GUI code still needs significant changes, but this will at least let you start seeing what you're dealing with.
public BoardSquare(int p, int q, String type)
{
this.setBorder(new LineBorder(Color.CYAN, 2));
this.setPreferredSize(new Dimension(100, 100));
// ... etc ...
BoardSquare seems to be coded to draw its contents based on coordinates from the absolute topmost leftmost point in the window, but they should be coded to draw themselves from the topmost leftmost point of the BoardSquare itself. That is, components should only draw within their own boundaries, and they should use coordinates that assume 0,0 designates the top,left of the component, not of the window.
If you want to use BoardSquares (JComponents) and add them to the frame, you probably should use a different layout manager, like GridLayout. FlowLayout won't give you the kind of precise positioning you want.
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
public class CheckersServer2
{
public static String type_BLANK = "BLANK";
public static String type_RED = "RED";
public static String type_BLACK = "BLACK";
public static int width = 100;
public static int height = 100;
public static class Board
{
private JFrame frame = new JFrame();
private JPanel backBoard = new JPanel();
Board()
{
int numRows = 8;
int numCols = 8;
frame.setSize(905,905);
backBoard.setSize(900,900);
frame.setTitle("Checkers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
backBoard.setVisible(true);
String type;
for(int r=0; r<numRows; r++){
for(int c=0; c<numCols; c++){
//
type = type_BLANK;
if(c%2==0){
if(r==0 || r==2) {
type = type_RED;
}else if(r==6){
type = type_BLACK;
}
}else{
if(r==1){
type = type_RED;
} else if(r==5 || r==7) {
type = type_BLACK;
}
}
backBoard.add(new BoardSquare(r,c,type));
}
}
backBoard.repaint();
frame.add(backBoard);
frame.repaint();
}
private class BoardSquare extends JComponent
{
/**
*
*/
private static final long serialVersionUID = 1L;
private int x; //x position of the rectangle measured from top left corner
private int y; //y position of the rectangle measured from top left corner
private boolean isBlack = false;
private boolean isRed = false;
public BoardSquare(int p, int q, String type)
{
//this.setBorder(new LineBorder(Color.CYAN, 2));
this.setPreferredSize(new Dimension(width, height));
x = p;
y = q;
if (type.equals(type_BLACK))
{
isBlack = true;
isRed = false;
}
else if (type.equals(type_RED))
{
isRed = true;
isBlack = false;
}
else if (type.equals(type_BLANK))
{
isBlack = false;
isRed = false;
}
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(x,y,width,height);
g2.draw(box);
g2.setPaint(Color.BLUE);
g2.fill(box);
int ovalWidth = width - 15;
int ovalHeight = ovalWidth;
if(isBlack)
{
g2.setColor(Color.black);
g2.fillOval(x, y, ovalWidth, ovalHeight);
g2.drawOval(x, y, ovalWidth, ovalHeight);
}
else if(isRed)
{
g2.setColor(Color.red);
g2.fillOval(x, y, ovalWidth, ovalHeight);
g2.drawOval(x, y, ovalWidth, ovalHeight);
}
}
}
}
public static void main(String[] args)
{
Board game = new Board();
}
}

Categories

Resources