I wrote a checkerboard program (shown below). My problem is that I can't figure out how to center it with resize, and have it resize proportionately.
I added in a short statement. Int resize (shown below) I did something similiar with a previous program regarding a bullseye where I used a radius. I just haven't the slightest clue how to implement that in here.
import java.awt.*;
import javax.swing.JComponent;
public class CheckerboardComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
int s = 12;
int x = s;
int y = s;
// int resize = Math.min(this.getHeight(), this.getWidth()) / 8 ;
for (int i = 0; i < 8; i++) {
// one row
for (int j = 0; j < 8; j++) {
g2.fill(new Rectangle(x, y, 4 * s, 4 * s) );
x += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
x = s;
y += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
}
}
here is a viewer program
import javax.swing.*;
public class CheckersViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(430, 450);
frame.setTitle("Checkerboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckerboardComponent component = new CheckerboardComponent();
frame.add(component);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hmm... Here's one idea then, though it probably isn't a good one (I'm also not that good with jComponent and jFrame, so there's probably a better way and a more suited person)
I believe the component object has a built-in method called getSize(). If you can relate the size of the rectangle to the size of the window, then it could be resizable. Obviously there would be more code and arguments, but for example:
public void drawStuff(Component c)
{
...
Dimension size = c.getSize();
double RectWidth = (size.width)*(.05);
...
}
check this out for more complete examples:
http://www.javadocexamples.com/java/awt/Component/getSize().html
And I apologize I can't be of more help.
Related
I am trying two draw a 2D array(dynamic) of random boxes with different colors,
this is the code:
Main.java
public class Main {
public static void main(String[] args) {
CustomPanel f = new CustomPanel (4, 5);
JFrame frame = new JFrame("Testing");
frame.add(f);
frame.setSize(1000, 1000);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
CustomPanel.java:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class CustomPanel extends JPanel {
Drawable [][]boxes;
public CustomPanel (int rows, int cols)
{
this.setLayout(null);
boxes = new Drawable[rows][cols];
Random rand = new Random();
for(int i = 0 ; i < rows ; i ++)
{
for(int j = 0 ; j < cols ; j++)
{
switch(rand.nextInt(3))
{
case 0:
boxes [i][j] = new Box1();
break;
case 1:
boxes [i][j] = new Box2();
break;
case 2:
boxes [i][j] = new Box3();
break;
}
}
}
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
Rectangle t = g.getClipBounds();
int box_width = t.width/ this.boxes[0].length;
int box_heigt = t.height/ this.boxes.length;
for(int i = 0 ; i < this.boxes.length; i ++)
{
for(int j = 0 ; j < this.boxes[0].length; j++)
{
System.out.println("" + i + ":" + j);
boxes [i][j].draw(i * box_width, j * box_heigt, box_width, box_heigt, g);
}
}
}
}
Drawable.java:
import java.awt.Graphics;
public interface Drawable {
public abstract void draw(int x, int y, int width, int height, Graphics g);
}
Box1(Box2, Box3 are the same, just different colors):
import java.awt.Color;
import java.awt.Graphics;
public class Box1 implements Drawable{
public Box1 () { //default constructor
}
#Override
public void draw(int x, int y, int width, int height, Graphics g) {
g.setColor(Color.CYAN);
g.fillRect(x, y, width, height);
}
}
The problem is that some of the boxes do not appear at the panel at all(altought I do iterate over both rows and columns).
I debugged it but could not find out why it happens(it might be silly - i know)
Box1(Box2, Box3 are the same, just different colors):
Don't create separate classes, just pass the Color as a parameter.
do you mean at paintComponent ? how? I guess this.getParent().getSize().width ?
Yes, paintComponent().
No, you don't get the parent. You are doing custom painting on a JPanel. You want the width/height of the panel using the methods I suggested in my comment.
The problem is that some of the boxes do not appear at the panel at all
You have your x/y values reversed when you paint each Box. The "i" variable represents the rows (or the y value) and the "j" variable represents the columns (or the x value).
So your logic should b:
for(int i = 0 ; i < this.boxes.length; i ++)
{
for(int j = 0 ; j < this.boxes[0].length; j++)
{
//boxes [i][j].draw(i * box_width, j * box_heigt, box_width, box_heigt, g);
boxes [i][j].draw(j * box_width, i * box_heigt, box_width, box_heigt, g);
}
}
instead of using the Array length property to control the rows/columns, why not just save the row/column parameters as variable in your class which might help make your code easier to read.
I tried to create a code that printed n random circles in a 500 x 500 frame but it didn't work.
Can somebody tell me why this code isn't running?
When I run this code, it lets me enter the number of random circles I want but the frame always appear to be empty - no circles are drawn.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.util.Scanner;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class RandomCircles extends JComponent
{
private int n;
public RandomCircles(int N)
{
n = N;
}
public void PaintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
double x = Math.random() * 500;
double y = Math.random() * 500;
double diameter = Math.random() * 500;
// Making sure the circle stays within the frame
for (int i = 0; i < n; i++)
{
while(x + diameter <= 500 || y + diameter <= 500)
{
Ellipse2D.Double circle
= new Ellipse2D.Double(x, y, diameter, diameter);
g2.draw(circle);
}
}
}
public static void main(String[]args)
{
Scanner in = new Scanner(System.in);
System.out.println("Enter number of circles here: ");
int n = in.nextInt();
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setTitle("Random Circles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RandomCircles circle = new RandomCircles(n);
frame.add(circle);
// Add PaintComponent method somewhere here?
frame.setVisible(true);
}
}
I have a feeling that I need to add in the public void PaintComponent(Graphics g) somewhere to print it out, but I am not sure how.
The problem is on this line:
public void PaintComponent(Graphics g)
You are attempting to override the paintComponent(Graphics) method. You need to be careful that you get the name and the parameters right. Notice you spelled your method with an upper case P.
It is advisable that you add the annotation #Override on methods that are supposed to override a super class' method. That way you get a notification if you get the signature wrong.
So your method should look like this:
#Override
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
...
}
== Edit after comments ==
The while loop is also causing an issue. Try doing this instead.
for (int i = 0; i < n; i++)
{
double x = Math.random() * 500;
double y = Math.random() * 500;
double diameter = Math.random() * 500;
Ellipse2D.Double circle
= new Ellipse2D.Double(x, y, diameter, diameter);
g2.draw(circle);
}
Notice that I moved the random number generation inside the loop. This does not guarantee the circle fitting in the frame but that is something you can modify later.
I am attempting to draw a checkerboard pattern in java using nested for loops, but I am having trouble doing it with two different colors. I know this question has been asked before, but it hasn't been asked with two different colors on the board that are not just using a background color. I plan on using the individual squares as an array to hold checker positions, so I do need each individual square made. Would it be better to drop the ice of a nested for loop to create each square, or should i stick with that shortcut? And if I were to stick with it, how would the nested loop be formatted (one for each color)?
When creating checker tiles, I would pass in an int for the x coordinate, and y coordinate such as:
import java.awt.Color;
import java.awt.Graphics;
public class CheckerTile {
public static final int WIDTH = 100; //width of each tile
public static final int HEIGHT = 100; //height of each tile, most likely same as width so its a square
public static int currentId = 0; //variable to reference unique id for each tile
private int id; //current id of tile
private int x; //x coordinate
private int y; //y coordinate
private int width; //width of tile
private int height; //height of tile
//Default constructor to take x and y coordinate
public CheckerTile( int x, int y ) {
this.id = currentId++;
this.x = x;
this.y = y;
width = WIDTH;
height = HEIGHT;
}
public int getId()
{
return id;
}
//draws the tile on the panel.
public void draw(Graphics g)
{
//if the checkerTile's id is divisible by 2, draw it red, otherwise draw it black.
g.setColor( id % 2 == 0 ? Color.RED : Color.black);
g.fillRect(x, y, width, height);
}
}
That way we have a way to draw the tile on the board. Now, when creating each object, we increment a currentId variable so that we can color each one individually using the modulus operator later.
I am assuming you are using Swing so I decided to add a draw(Graphics g) method so when repainting in java it would use that Graphics object. If you are using a different library, then you will have to do some research in to how to draw it on the board.
Now in your JPanel, it would look something like this:
//Creates the JPanel, which needs to be added to JFrame object in main
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CheckerBoard extends JPanel {
CheckerTile[][] checkerTiles; //2-dimension array of checkerTiles
public CheckerBoard() {
super();
this.setSize(800,800);
checkerTiles = new CheckerTile[9][9];
//This creates the checkerTiles.
for(int i = 0; i < 9; i++)
{
for( int j = 0; j < 9; j++)
{
checkerTiles[i][j] = new CheckerTile( j * CheckerTile.WIDTH, i * CheckerTile.HEIGHT );
}
}
this.setVisible(true);
//Repaint right away to show results.
repaint();
}
//We need to override this to paint the tiles on the board.
#Override
public void paintComponent(Graphics g)
{
for(int i = 0; i < checkerTiles.length; i++)
{
for(int j = 0; j < checkerTiles[i].length; j++)
{
//call the draw method on each tile.
checkerTiles[i][j].draw(g);
}
}
}
//A demo of adding the panel to a frame and showing the tiles.
public static void main(String[] args)
{
//Create the JFrame and add the CheckerBoard we made to it.
JFrame frame = new JFrame();
frame.setSize(800,800);
frame.setLayout(new BorderLayout());
frame.add(new CheckerBoard(), BorderLayout.CENTER);
frame.setVisible(true);
}
}
This is probably an elementary question. However, I have completed reading the 9th Chapter of Java Programming for the Absolute Beginner and have approached the Challenges section. I cannot quite get the progam to show a gradient from dark to light.
The question asks:
"Create a Canvas that paints a gradient that's dark on one side and slowly gets lighter
as it moves to the other side."
I have looked at the Java Challenge on Creating a Canvas page (which I asked about before) and got a better understanding of creating a color gradient canvas, however, I am still having great difficulty.
I think that my main problem is how to get the gray colors in between as the program shows a completely black square or when run with just the first for loop, a completely white square. I THINK THAT MY FOR LOOPS ARE PROBLEMATIC AND DO NOT CORRECTLY IDENTIFY THE VARIABLES.
An answer to this question can potentially aid many new Java programmers in understanding Graphics and Canvas.
I do not know JFrame, Swing, Points, JPanels, BufferedImage, or GradientPaint.
Thank you very much for your time and cooperation reagrding this matter.
HERE IS THE CODE:
import java.awt.*;
public class RandomColorSquare extends GUIFrame {
Canvas slight;
public final static int MIN = 0,
MAX = 225;
public RandomColorSquare(int r, int g, int b) {
super("Random Color Square");
r = r >= MIN && r <= MAX ? r : MIN;
g = g >= MIN && g <= MAX ? g : MIN;
b = r >= MIN && b <= MAX ? b : MIN;
slight = new Canvas();
slight.setBackground(new Color(r,g, b));
slight.setSize(200, 150);
add(slight, BorderLayout.CENTER);
for(r=0; r<225; r++) {
Color c = slight.getBackground().brighter();
slight.setBackground(c);
}
for (g=0; g<225; g++) {
Color d = slight.getBackground().darker();
slight.setBackground(d);
}
for (b=0; b<225; b++) {
Color e = slight.getBackground().darker();
slight.setBackground(e);
}
pack();
setVisible(true);
}
public static void main(String args[]) {
if (args.length != 3) {
new RandomColorSquare(0, 0, 0);
}
else {
new RandomColorSquare(Integer.parseInt(args[0]), Integer.parseInt(args[1]),
Integer.parseInt(args[2]));
}
}
}
First of all, as I mentioned in the comment, when you setBackground you are changing the background of the Canvas, not adding to it. So whatever you set it to last is what you see. In your case, that is the darkest form of blue, which is just black. If you comment out the last two loops, you get a white background (the brightest red).
However. Using only what you know this is the best I can come up with. It involves creating your own custom Canvas, which I called CustomCanvas. In there, you can override the paint method and keep drawing progressively lighter filled rectangles across the screen. Here's a small sample to help you understand what I mean:
class CustomeCanvas extends Canvas{
public void paint(Graphics g){
Color background = new Color(30,30,120); //Set this accordingly
for(int i=0;i<getWidth();i++){
g.setColor(background);
background = getBrighter(background);
g.fillRect(i,0, 1, getHeight());
}
}
private Color getBrighter(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
if(r< MAX) r+=1;
if(g< MAX) g+=1;
if(b< MAX) b+=1;
return new Color(r,g,b);
}
}
Which produces this background:
I still recommend reading about GradientPaint which makes this process a lot easier and nicer.
You can override paint() in your Canvas in a manner similar to how this example does for Panel. In your implementation, use drawImage() to render a BufferedImage in which you've used setRGB() to construct your gradient.
Addendum: The example below illustrates the approach by creating a random image. You can create a gradient similarly.
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/** #see https://stackoverflow.com/a/14096121/230513 */
public class AWTImage {
public static void main(String[] args) throws IOException {
Frame frame = new Frame();
frame.add(new ImageCanvas());
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
private static class ImageCanvas extends Canvas {
private static final Random r = new Random();
private BufferedImage image;
public ImageCanvas() {
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
for (int row = 0; row < image.getHeight(); row++) {
for (int col = 0; col < image.getWidth(); col++) {
image.setRGB(col, row, r.nextInt());
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
}
}
}
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();
}
}