I understand how to make 2d array grid. I experimented to put random numbers in it but i do not know how to draw them on jframe. For instance, 0 for red circle , 1 for green circle and so on. I need to figure out how represent them in grid manner too.
public class Game {
public static void initGrid(){
//clumn and row 4 x 4
int col = 4;
int row = 4;
//initialize 2d grid array
int[][] a = new int[row][col];
Random rand = new Random();
//for loop to fill it with random number
for(int x = 0 ; x < col ; x++) {
for(int y = 0; y < row; y++) {
a[x][y] = (int) rand.nextInt(4);
System.out.print(a[x][y]);
}//inner for
System.out.println();
}//outer for
}//method
public static void main(String[] args){
initGrid();
}
}
I understand JFrame and JPanel as far as drawing on empty canvas but not the way i want. I want to combine both code but my knowledge is limited.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game2 extends JPanel{
#Override
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.RED);
g2d.fillOval(0, 0, 30, 30);
g2d.drawOval(0, 50, 30, 30);
g2d.fillRect(50, 0, 30, 30);
g2d.drawRect(50, 50, 30, 30);
g2d.draw(new Ellipse2D.Double(0, 100, 30 ,30));
}
public static void main(String[] args){
JFrame frame = new JFrame("Mini Tennis");
frame.add(new Game2());
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
My suggestion is:
Pass the Game class as a parameter to the constructor of Game2 and store it as a local variable in the Game2 class as illustrated below:
Game game;
public Game2(Game game){
this.game = game;
//Rest of your constructor.
}
Next you declare a getter method in the Game class to retrieve the array which stores the position grid like as below:
public int[][] getPositions(){
return this.a;
}
Create a method that will return the colour to paint based on the int value stored as the element of the grid like this:
private Color getColor(int col){
switch(col){
case 0:
return Color.red;
case 1:
.
.
.
.
}
}
Now instead of overriding the paint method of your Game2 class override the paintComponent and draw the circles in the paintComponent method as illustrated(Here I have considered the circles to be of 30px diameter with a gap of 20px between them):
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int[][] pos = this.game.getPositions();
for(int i = 0; i < pos.length; i++){
for(int j = 0; j < pos[i].length; j++){
g2d.setColor(getColor(pos[i][j]));
g2d.fillOval(i*50, j*50, 30, 30);
}
}
}
I hope this will solve your problem of accessing the Game representing the model from the Game2 class representing the view.
Related
The following is an example using drawLine() to draw horizontal and vertical dashed lines on a JPanel.
As the JPanel is resized, so are the dashed lines.
Here is the main object.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class ExampleForPosting implements Runnable{
public static void main(String args[]) {
SwingUtilities.invokeLater(
new ExampleForPosting ());
}
private LineDrawer panel;
#Override
public void run() {
JFrame frame = new JFrame("Line Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new LineDrawer();
panel.setPreferredSize(new Dimension(300, 200));
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void setJPanelBackground(Color color) {
panel.setBackground(color);
panel.repaint();
}
}
This is the JPanel which does the drawing.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import javax.swing.JPanel;
public class LineDrawer extends JPanel
{
private Stroke dashedLineStroke = getDashedLineStroke(1);
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.setStroke(dashedLineStroke);
for (int i = 1; i < (this.getWidth()-10) ; i++)
g.drawLine(10, (i*10), this.getWidth()-10, (i*10));
for (int i = 1; i < (this.getHeight()-10) ; i++)
g.drawLine((i*10), 10, (i*10), this.getHeight()-10);
}
public Stroke getDashedLineStroke(int width)
{
float[] dashPattern = {2, 2};
return new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2, dashPattern, 0);
}
}
For the most part. It works.
As the panel increases in size so do the dashed lines.
The issue is depending upon where the panel is stopped when resizing, it can be incomplete as shown here by the highlights or there isn't an equal amount of space from the edge.
The objective would be to make this dynamic so that the dashed lines always complete and same spacing on all sides.
If need be the spacing could be modified, but it should be dynamic even if the properties of the dashed line are changed.
I suspect there is some other attribute required for the calculation but unable to find one that works.
for (int i = 1; i < (this.getWidth()-10) ; i++)
First of all your looping condition is wrong. If your width is 300, then you would loop 289 times. You need to divide the width by 10 to get the number of lines to draw.
so that the dashed lines always complete and same spacing on all sides.
Well that is not possible. If the width is 105 and each border is 10, then the width of the last line segment can only be 5.
The easiest way to solve the problem is to set the clip bounds of your painting. Then any drawing outside of the clipped area will be ignored.
This will allow a partial line to be drawn as the frame is resized:
Rectangle clip = new Rectangle(10, 10, getWidth() - 19, getHeight() - 19);
g.setClip( clip );
int linesX = getHeight() / 10;
int linesY = getWidth() / 10;
for (int i = 1; i < linesX ; i++)
g.drawLine(10, (i*10), this.getWidth(), (i*10));
for (int i = 1; i < linesY ; i++)
g.drawLine((i*10), 10, (i*10), this.getHeight()-10);
I was practicing moving graphics in Java and I seem to be coming to a problem. What I drew right now is 2 alien faces. At the moment my program is set up to move the faces 1 step at a time in a certain direction based on user input. What I would like to do is have the alien faces move from point A to point B. For example, right now it moves 1 step at a time because I have the parts of the faces increase by 1 on it's x and y. My thoughts were to start a loop before the method MoveHorizontal(), that way it would run so many times and I would have a smooth transition from one point to another. It's not working like that for me though. It would skip from where it started to where the loops ends rather than 1 step at a time. So my question is, how would I be able to do that? lol. Thank you.
//First Class
import javax.swing.JFrame;
import java.util.Scanner;
public class AlienFace
{
public static void main(String[] args)
{
String userInput;
Scanner input = new Scanner(System.in);
JFrame frame = new JFrame();
frame.setSize(700, 700);
frame.setTitle("An Alien Face");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FaceComponent component = new FaceComponent();
frame.add(component);
frame.setVisible(true);
System.out.println("Which direction would you like the Alien faces to move? ");
System.out.print("H/h for horizontally, V/v for vertically, D/d for diagonally, or Q/q to quit: ");
userInput = input.nextLine();
System.out.println(userInput);
while (!userInput.equals("q") || !userInput.equals("Q"))
{
System.out.println("Which direction would you like the Alien faces to move? ");
System.out.print("H/h for horizontally, V/v for vertically, D/d for diagonally, or Q/q to quit: ");
userInput = input.nextLine();
if (userInput.equals("H") || userInput.equals("h"))
{
component.MoveHorizontal();
frame.repaint();
}
if (userInput.equals("V") || userInput.equals("v"))
{
component.MoveVertical();
frame.repaint();
}
if (userInput.equals("D") || userInput.equals("d"))
{
component.MoveDiagonal();
frame.repaint();
}
}
if (userInput.equals("q") || userInput.equals("Q"))
{
frame.setVisible(false);
}
}
}
//Second Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
public class FaceComponent extends JComponent
{
int head2X = 5;
int head2Y = 10;
int head3X = 105;
int head3Y = 115;
int eye2X = 25;
int eye2Y = 75;
int eye3X = 125;
int eye3Y = 175;
int mouth2X1 = 30;
int mouth2Y1 = 110;
int mouth3X1 = 130;
int mouth3Y1 = 210;
int mouth2X2 = 80;
int mouth2Y2 = 110;
int mouth3X2 = 180;
int mouth3Y2 = 210;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Graphics2D g3 = (Graphics2D) g;
Ellipse2D.Double head = new Ellipse2D.Double(head2X, head2Y, 100, 150);
g2.draw(head);
Ellipse2D.Double head1 = new Ellipse2D.Double(head3X, head3Y, 100, 150);
g3.draw(head1);
g2.setColor(Color.GREEN);
Rectangle eye = new Rectangle(eye2X, eye2Y, 15, 15);
g2.fill(eye);
eye.translate(50, 0);
g2.fill(eye);
g3.setColor(Color.GREEN);
Rectangle eye1 = new Rectangle(eye3X, eye3Y, 15, 15);
g3.fill(eye1);
eye1.translate(50, 0);
g3.fill(eye1);
Line2D.Double mouth = new Line2D.Double(mouth2X1, mouth2Y1, mouth2X2, mouth2Y2);
g2.setColor(Color.RED);
g2.draw(mouth);
Line2D.Double mouth1 = new Line2D.Double(mouth3X1, mouth3Y1, mouth3X2, mouth3Y2);
g3.setColor(Color.RED);
g3.draw(mouth1);
g2.setColor(Color.BLUE);
g2.drawString("Hello, World!", 5, 175);
}
public void MoveHorizontal()
{
head2X++;
head3X++;
eye2X++;
eye3X++;
mouth2X1++;
mouth3X1++;
mouth2X2++;
mouth3X2++;
}
public void MoveVertical()
{
head2Y++;
head3Y++;
eye2Y++;
eye3Y++;
mouth2Y1++;
mouth3Y1++;
mouth2Y2++;
mouth3Y2++;
}
public void MoveDiagonal()
{
head2X++;
head3X++;
eye2X++;
eye3X++;
mouth2X1++;
mouth3X1++;
mouth2X2++;
mouth3X2++;
head2Y++;
head3Y++;
eye2Y++;
eye3Y++;
mouth2Y1++;
mouth3Y1++;
mouth2Y2++;
mouth3Y2++;
}
}
I have every part of this program working except for the colors. Right now I have it repainting any random color and I need it to only paint the lines yellow, green, or blue. Can someone lead me in the right direction please?
`package ColoredLines;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
import java.awt.Color;
#SuppressWarnings("serial")
public class ColoredLines extends JPanel {
private final Random rand = new Random();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Random rand = new Random();
super.paintComponent(g);
this.setBackground(Color.BLACK);
for(int i = 10; i < 410; i += 20){
for(int j = 0; j < 410; j += 410){
g.setColor(new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256)));
g.fillRect(i, j, 10, 410);
}
}
}
}
`
Make an ArrayList of the three colors:
ArrayList<Color> colors = new ArrayList<Color>();
Add three colors with: colors.add(new Color(r,g,b)
To select a random color using:
Random rand = new Random();
Color randomColor = colors[rand.nextInt(2)];
Note: in rand.nextInt(2); the random number could be 0, so the possible numbers are three (0,1,2).
Trying to figure out the best way to do this (And without crossing any specifics DO NOTs that I don't know about).
I'm working on visually displaying a graph (Various nodes, with edges connecting them) with circles and lines to represent such. Each node will be added during runtime and I can't hardcode this. From what I understand, all painting needs to be done in the paint(Graphics g) method - which isn't that helpful, since I can't be change the parameters and it seems this is only called during the initial creation?
Right now I was thinking about having it call various other methods, passing the Graphics object, and depending on other variables - I'll decide whether that's what I even want to call (Since the paint() method is the only one I can call).
Am I going about this completely wrong? Never bothered with this before.
To give you a better idea of what I want to end up with: I want to be able to pass the coordinates of the shape I want to add for the node, and then add it to whatever I have on the graph so far. And then same with the edges, I want to be able to pass the beginning and end point of the line to repaint on top of whatever is existing at that time.
Not exactly what I want right now - but you'll get the idea from what I patched together so far:
import java.awt.*;
import javax.swing.*;
public class MyCanvas extends Canvas
{
public MyCanvas()
{
}
public void paint(Graphics graphics)
{
// Keep this until I figured out if it's painted on load or not.
graphics.drawLine(10, 20, 350, 380);
}
public static void main(String[] args)
{
MyCanvas canvas = new MyCanvas();
JFrame frame = new JFrame();
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
frame.setSize(canvasSize, canvasSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(canvas);
frame.setVisible(true);
}
public void drawNode(int x, int y, Graphics g)
{
// Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
g.setColor(Color.white);
g.fillOval(xLoc, yLoc, 8, 8);
g.drawOval(xLoc, yLoc, 8, 8);
}
public void drawArc(int x, int y, int xx, int yy, Graphics g)
{
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
int xxLoc = (xx*10) - 5;
int yyLoc = (yy*10) - 5;
g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
}
}
Edit: (Response for Andrew)
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyCanvas extends JPanel
{
public MyCanvas() {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
public static void main(String[] args)
{
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
JFrame frame = new JFrame();
JLabel label = new JLabel();
BufferedImage bImage = new BufferedImage(canvasSize, canvasSize, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bImage.createGraphics();
g2d.drawLine(50, 50, 300, 300);
ImageIcon iIcon = new ImageIcon(bImage);
label.setIcon(iIcon);
frame.add(label);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g2d = drawNode(1,1,g2d);
label.repaint();
}
public static Graphics2D drawNode(int x, int y,Graphics2D g2d)
{
// Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
g2d.setColor(Color.white);
g2d.fillOval(xLoc, yLoc, 8, 8);
g2d.drawOval(xLoc, yLoc, 8, 8);
return g2d;
}
public static void drawArc(int x, int y, int xx, int yy)
{
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
int xxLoc = (xx*10) - 5;
int yyLoc = (yy*10) - 5;
// g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
}
}
There are various strategies you might pursue for this.
If the objects are never removed from the drawing once done, use a BufferedImage, put it in a (ImageIcon in a) JLabel. When it comes time to update:
Get the graphics instance of the image and draw the new element.
Dispose of the graphics object.
Call repaint() on the label.
Keep a list of the drawn elements. In the paint method, paint them all. When a new element is added, call repaint() on the rendering component.
Here is an example of the 1st technique:
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class MyCanvas
{
JLabel view;
BufferedImage surface;
Random random = new Random();
public MyCanvas()
{
surface = new BufferedImage(600,400,BufferedImage.TYPE_INT_RGB);
view = new JLabel(new ImageIcon(surface));
Graphics g = surface.getGraphics();
g.setColor(Color.ORANGE);
g.fillRect(0,0,600,400);
g.setColor(Color.BLACK);
// Keep this until I figured out if it's painted on load or not.
g.drawLine(10, 20, 350, 380);
g.dispose();
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addNewElement();
}
};
Timer timer = new Timer(200, listener);
timer.start();
}
public void addNewElement() {
boolean drawArc = random.nextBoolean();
int x = random.nextInt(60);
int y = random.nextInt(40);
Graphics g = surface.getGraphics();
if (drawArc) {
g.setColor(Color.BLUE);
int xx = random.nextInt(60);
int yy = random.nextInt(40);
drawArc(x,y,xx,yy,g);
} else {
drawNode(x,y,g);
}
g.dispose();
view.repaint();
}
public static void main(String[] args)
{
MyCanvas canvas = new MyCanvas();
JFrame frame = new JFrame();
int vertexes = 0;
// Change this next part later to be dynamic.
vertexes = 10;
int canvasSize = vertexes * vertexes;
frame.setSize(canvasSize, canvasSize);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(canvas.view);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void drawNode(int x, int y, Graphics g)
{
// Treat each location as a 10x10 block. If position 1,1 then go to (5,5) - If position 3,5 then go to (25, 45) eg: (x*10)-5, (y*10)-5
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
g.setColor(Color.white);
g.fillOval(xLoc, yLoc, 8, 8);
g.drawOval(xLoc, yLoc, 8, 8);
}
public void drawArc(int x, int y, int xx, int yy, Graphics g)
{
int xLoc = (x*10) - 5;
int yLoc = (y*10) - 5;
int xxLoc = (xx*10) - 5;
int yyLoc = (yy*10) - 5;
g.drawLine(xLoc, yLoc, xxLoc, yyLoc);
}
}
Further tip
You might notice that the lines look quite 'jagged' & ugly. Both the BufferedImage or a JComponent has access to the more useful Graphics2D object (for the JComponent it is necessary to cast it in paintComponent()). A Graphics2D instance accepts rendering hints that can be used to smooth (dither) the elements drawn.
Which method is the best way to create a pixel image with java.
Say, I want to create a pixel image with the dimensions 200x200 which are 40.000 pixels in total. How can I create a pixel from a random color and render it at a given position on a JFrame.
I tried to create a own component which just creates pixel but it seems that this is not very performant if I create such a pixel a 250.000 times with a for-loop and add each instance to a JPanels layout.
class Pixel extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getRandomColor());
g.fillRect(0, 0, 1, 1);
}
}
You do not need to create a class for this. Java already has the excellent BufferedImage class that does exactly what you need. Here is some pseudo-code:
int w = 10;
int h = 10;
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage image = new BufferedImage(w, h, type);
int color = 255; // RGBA value, each component in a byte
for(int x = 0; x < w; x++) {
for(int y = 0; y < h; y++) {
image.setRGB(x, y, color);
}
}
// Do something with image
The key here is the Canvas class. It is the standard Component that allows arbitrary draw operations. In order to use it, you must subclass the Canvas class and override the paint(Graphics g) method, then loop through each pixel and draw your random color. The following code should work:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
public class PixelCanvas extends Canvas {
private static final int WIDTH = 400;
private static final int HEIGHT = 400;
private static final Random random = new Random();
#Override
public void paint(Graphics g) {
super.paint(g);
for(int x = 0; x < WIDTH; x++) {
for(int y = 0; y < HEIGHT; y++) {
g.setColor(randomColor());
g.drawLine(x, y, x, y);
}
}
}
private Color randomColor() {
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(WIDTH, HEIGHT);
frame.add(new PixelCanvas());
frame.setVisible(true);
}
}
The generated image looks like this:
You'll probably want to create a BufferedImage of the size you want, and use img.setRGB(x, y, getRandomColor()) to create a bunch of random pixels. Then you could render the whole image wherever you want it.