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);
Related
I've gotten my code to work for the most part except for one last thing. When the number of lines drawn > 20, the lines aren't being drawn to take up the full amount of panel
** Look at the bottom right side of my screenshot. The lines go part way down the full height of the panel. I need it to go the full length of the height down. **
Here's my code for DrawPanelTest
// Creating JPanel to display DrawPanel
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class DrawPanelTest
{
public static void main(String[] args)
{
int nValue = 0; // declare variable to store user input. Default value 0.
Boolean flag = true; // initalize flag to true for argument value of while-loop
// while-loop to prompt user input
while (flag) {
// prompt user for the value of N
nValue = Integer.parseInt(JOptionPane.showInputDialog("Enter number of lines between 2 and 100."));
// user input validation. Valid input is nValue [2, 100]
if (nValue < 2 || nValue > 100) {
nValue = Integer.parseInt(JOptionPane.showInputDialog("Enter number of lines between 2 and 100."));
} else {
flag = false; // if user input is correct, while-loop will end
} // end if-else
} // end while-loop
// displays the value of N to make sure it really is correct; This works
// String message = String.format("The value of n is: %d ", nValue);
// JOptionPane.showMessageDialog(null, message);
// create a panel that contains our drawing
DrawPanel drawPanel = new DrawPanel(nValue);
// create a new frame to hold the panel
JFrame application = new JFrame();
// set the frame to exit when closed
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(drawPanel); // add panel to the frame
application.setSize(600, 600); // set the size of the frame
application.setVisible(true); // make the frame visible
}
} // end class DrawPanelTest
Here's my code DrawPanel
// Using drawLine() to connect the corners of a panel
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel
{
int numLines;
// constructor initializes DrawPanel and initializes
// numLines with the argument value of n
public DrawPanel(int n)
{
numLines = n;
}
// draws a X from the corners of the panel
public void paintComponent( Graphics g)
{
// call paintComponent to ensure the panel displays correctly
super.paintComponent(g);
int width = getWidth(); // total width
int height = getHeight(); // total height
int x1 = 0; // starting x-coordinate
int y1 = height / 2; // starting y-coordinate
int x2 = width; // initial value for end x-coordinate
int spaceValue = 0; // represents the space between the lines
int stepValue = height/numLines; // represents the increment value starting from top right corner
for (int i = 0; i <= numLines; i++) {
if (numLines == 2) {
g.drawLine(x1, y1, x2, 0);
g.drawLine(x1, y1, x2, height);
break;
} // end numLines == 2
else if (numLines >= 3) {
g.drawLine(x1, y1, x2, spaceValue);
spaceValue += stepValue;
} // end else if
} // end for-loop
} // end paintComponent
} // end class DrawPanel
I think my problem lies in DrawPanel line 41. I don't think I'm calculating the spaces between the lines correctly so that they end up taking the entire height of the panel.
Thanks in advance for your help.
Your calculation of the "stepValue" has two problems:
the stepValue is to small, so the last line will never appear at the bottom
the stepValue is truncated because of integer math so each addition of the truncated value to the "spaceValue" will yield a slightly less accurate value.
Lets say you have a panel with a height of 600 and the number of lines is 3.
Your calculation is:
int stepValue = 600 / 3 = 200
which I would suggest is wrong as you would draw 3 lines with a "spaceValue" of 0, 200, 400, so the last line (at 600) would never be drawn.
In reality I think the calculation should be:
double stepValue = (double)height / (numLine - 1);
which gives:
double stepValue = 600 / (3 - 1) = 300.
which will give lines with a "spaceValue" of 0, 300, 600 which would be a line at the top, middle and bottom.
So your painting loop simply becomes:
for (int i = 0; i < numLines; i++)
{
g.drawLine(x1, y1, x2, spaceValue);
spaceValue += stepValue;
}
I think (one of) the issue you're having is a "integer division" issue.
int stepValue = height / numLines;
is truncating the result. For example, if the height is 400 and the number of lines is 6 the stepValue will be 66 instead of 67 (which would allow 66.6666 to be rounded up)
Now, you could "round" the value up yourself, but I'd prefer to make use of the available APIs to do these things for me.
Line2D.Double supports double precision parameters, which makes it perfect for this job
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (lineCount > 1) {
double gap = getHeight() / (double)(lineCount - 1);
for (int i = 0; i < lineCount; i++) {
Line2D line = new Line2D.Double(0, getHeight() / 2, getWidth(), i * gap);
g2d.draw(line);
}
} else {
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
}
g2d.dispose();
}
Runnable example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(32, 32, 32, 32));
frame.setContentPane(contentPane);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int lineCount = 1;
public TestPane() {
setBorder(new LineBorder(Color.RED));
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
lineCount++;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(Integer.toString(lineCount), 10, fm.getAscent());
if (lineCount > 1) {
double gap = getHeight() / (double) (lineCount - 1);
for (int i = 0; i < lineCount; i++) {
Line2D line = new Line2D.Double(0, getHeight() / 2, getWidth(), i * gap);
g2d.draw(line);
}
} else {
g2d.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
}
g2d.dispose();
}
}
}
In the for loop, change
for (int i = 0; i < numLines; i++) {
to
for (int i = 0; i <= numLines; i++) {
to iterate the full height of the component. The i must equal numLines to reach unity.
I'm drawing a minimap for a game and every 40x40 pixels in the game is a pixel on the minimap.
The problem starts when I have a screen which uses windows 10 scaling for example of 125% scaling.
Pixels drawn with g.drawLine(x,y,x,y) fill 1 pixel in a 2x2 space with scaling 125%, but are adjacent with 100% scaling.
https://prnt.sc/10uiez6
https://prnt.sc/10uieai
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WindowsScaleTesting {
public static void main(final String[] args) {
final JFrame frame = new JFrame("windows 10 scaling minimum example line");
frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
final JPanel board = new JPanel() {
#Override
public void paint(final Graphics g) {
for(int x = 0; x < 100; x++) {
for(int y = 0; y < 100; y++) {
g.setColor(Color.gray);
g.drawLine(x, y, x, y);
}
}
}
};
board.setSize((1900),(1070));
board.setDoubleBuffered(true);
frame.add(board);
frame.setSize((1900),(1070));
frame.setVisible(true);
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
}
}
Pixels drawn with g.drawRect(x,y,1,1) fill 3 pixels in a 2x2 space with scaling 125%, but are adjacent with 100% scaling.
https://prnt.sc/10uig1w
https://prnt.sc/10uieai
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WindowsScaleTesting2 {
public static void main(final String[] args) {
final JFrame frame = new JFrame("windows 10 scaling minimum example rectangle");
frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);
final JPanel board = new JPanel() {
#Override
public void paint(final Graphics g) {
for(int x = 0; x < 100; x++) {
for(int y = 0; y < 100; y++) {
g.setColor(Color.gray);
g.drawRect(x, y, 1, 1);
}
}
}
};
board.setSize((1900),(1070));
board.setDoubleBuffered(true);
frame.add(board);
frame.setSize((1900),(1070));
frame.setVisible(true);
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
}
}
To reproduce the pictures above you need 2 screens with different scaling (100% and 125%) or you need to have 1 screen and switch the scaling from 100% to 125%.
How do I draw pixels with no spaces in between on 125% or other scaling and how do I recognize windows 10 scaling in java?
One solution to the problem is to fix the scaling in the vm arguments.
Adding -Dsun.java2d.uiScale=1.0 as a vm argument to the programm in eclipse solves the scaling issue, credits to Christian Hujer in this answer https://superuser.com/a/1194728/377633
I am trying to create a Billiards game for my project and I am having difficulty in adding the stick and the balls at the same time. Also, when I add the balls the background of the JFrame goes white, it is actually supposed to be green (the color of the table).
Your help will be much appreciated.
I tried using Graphics. For example g2d.setBackground(Color.green). Which did not work
public class Practice_Window implements MouseListener, MouseMotionListener, KeyListener {
JFrame Practice_Mode = new JFrame();
Balls myBalls = new Balls();
Stick myStick = new Stick();
public void PracticeWindow()
{
Practice_Mode.setSize(1000, 500);
Practice_Mode.setVisible(true);
Practice_Mode.setResizable(false);
Practice_Mode.setTitle("Practice Mode");
Practice_Mode.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Practice_Mode.getContentPane().setBackground(new Color(0, 1, 0, 0.5f)); //Not visible after i add my balls
Practice_Mode.getRootPane().setBorder(BorderFactory.createMatteBorder(10, 10, 10, 10, Color.GREEN));
Practice_Mode.add(myBalls);
//Practice_Mode.add(myStick);
//JPanel p = new JPanel();
//Timer t= new Timer(10, myBalls);
}
//BALL CLASS
public class Balls extends JPanel implements ActionListener
{
double Size = 35;
double REDxSpeed = 5;
double REDySpeed = 5;
double REDSpeed = 0;
double YELLOWxSpeed = 2;
double YELLOWySpeed = 3;
double YELLOWSpeed = 0;
double WHITExSpeed = 4;
double WHITEySpeed = 2;
double WHITESpeed = 0;
double friction = 0.2;
boolean Collision = false;
Ellipse2D.Double red = new Ellipse2D.Double(200, 200, Size, Size);
Ellipse2D.Double yellow = new Ellipse2D.Double(300, 300, Size, Size);
Ellipse2D.Double white = new Ellipse2D.Double(150, 400, Size, Size);
Timer t = new Timer(10, this);
Balls()
{
t.start();
}
#Override
public void actionPerformed(ActionEvent e) //Things are moving here
{
//RED BALL
red.x += REDxSpeed;
red.y += REDySpeed;
REDSpeed = Math.sqrt(REDxSpeed*REDxSpeed + REDySpeed*REDySpeed);
repaint();
if(red.x < 0 || red.x > getWidth() - red.width)
{
REDxSpeed = -REDxSpeed;
}
if(red.y < 0 || red.y > getHeight() - red.height)
{
REDySpeed = -REDySpeed;
}
//YELLOW BALL
yellow.x += YELLOWxSpeed;
yellow.y += YELLOWySpeed;
YELLOWSpeed = Math.sqrt(YELLOWxSpeed*YELLOWxSpeed + YELLOWySpeed*YELLOWySpeed);
repaint();
if(yellow.x < 0 || yellow.x > getWidth() - yellow.width)
{
YELLOWxSpeed = -YELLOWxSpeed;
}
if(yellow.y < 0 || yellow.y > getHeight() - yellow.height)
{
YELLOWySpeed = -YELLOWySpeed;
}
//WHITE BALL
white.x += WHITExSpeed;
white.y += WHITEySpeed;
WHITESpeed = Math.sqrt(WHITExSpeed*WHITExSpeed + WHITESpeed*WHITEySpeed);
repaint();
if(white.x < 0 || white.x > getWidth() - white.width)
{
WHITExSpeed = -WHITExSpeed;
}
if(white.y < 0 || white.y > getHeight() - white.height)
{
WHITEySpeed = -WHITEySpeed;
}
Collision_Detection();
}
public void paintComponent(Graphics g) //DRAWING MY BALLS
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
//g2d.setBackground(Color.green);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.red);
g2d.fill(red);
g2d.setColor(Color.yellow);
g2d.fill(yellow);
g2d.setColor(Color.black);
g2d.fill(white);
}
//STICK CLASS
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class Stick extends JPanel implements MouseListener, MouseMotionListener, ActionListener {
int xLocation = 50;
int yLocation = 50;
int Width = 50;
int Height = 15;
Rectangle2D.Double stick = new Rectangle2D.Double(200, 200, Width, Height);
Timer t = new Timer(10, this);
Stick()
{
t.start();
}
public void PaintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.ORANGE);
g2d.fill(stick);
}
I am having difficulty in adding the stick and the balls at the same time.
So why are you trying to write your entire application at once without doing any testing along the way? Why do you have Timers in the code? Why do you have KeyListeners?
Learn to develop applications one step at a time. Write a little code do some testing. When it works add more functionality. Get the basic right first before adding more complicated logic.
Practice_Mode.add(myBalls);
//Practice_Mode.add(myStick);
The default layout manager of a JFrame is the BorderLayout. By default, when you add a component to the frame (and don't specify a constraint) the component goes to the CENTER. Only a single component can be added to the CENTER so only the last component added will be visible.
Your basic design is wrong. You don't want to have separate panels for the balls and stick. You want to have a single "BilliardsGameBoard" panel that will paint multiple objects. So this panel will paint all the balls and the stick. This way all the objects are managed by the same class.
You should also not be creating individual objects with variable names. This limits the number of object you can control. Instead, keep the objects you want to paint in an ArrayList, then the painting method iterates through the ArrayList and paints each object.
See: get width and height of JPanel outside of the class for a working example of this approach.
I add the balls the background of the JFrame goes white,
Practice_Mode.getContentPane().setBackground(new Color(0, 1, 0, 0.5f));
Don't use alpha values when you specify your color. For green you can just use:
practiceMode.getContentPane().setBackground( Color.GREEN );
Your stick and balls are extending JPanel, which is typically used as a container to group a bunch of JComponents, which are buttons and UI elements. The graphical errors you see is likely Java trying to line up your panels side by side using the default BorderLayout, because it thinks you want panels of buttons and stuff when you are just trying to achieve freeform shapes.
A better approach would be to to render your stick and balls as primitive shapes on a JPanel, rather than as JPanels themselves. This is accomplished by making them implement Shape or at least giving them draw methods; the Primitives tutorial would be of use. This question also has somebody in a somewhat similar situation as yourself, and has answers relevant to you.
I have a graphic which consists of a horizontal line of circles of different sizes at regular intervals. Here is the picture:
I am trying to recreate this graphic using recursion as opposed to the if statements used in my code but after trying, am unsure about how to do this. Would love some help, here is my code:
package weekFour;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
#SuppressWarnings("serial")
public class Circle extends JPanel {
private int circX = 10;
private static int windowW = 1700;
private static int windowH = 1000;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //smoothes out edges
Color c5 = new Color(50, 50, 50);
Color c4 = new Color(100, 100, 100);
Color c3 = new Color(150, 150, 150);
Color c2 = new Color(200, 200, 200);
Color c1= new Color(250, 250, 250);
for (int i = 0; i < 1; i++) {
g2.setColor(c1);
g2.fillOval(522 + 75*i, 138, 666, 666);
g2.setColor(c1);
g2.drawOval(522 + 75*i, 138, 666, 666);
}
for (int i = 0; i < 3; i++) {
g2.setColor(c2);
g2.fillOval(244 + 522*i, 365, 180, 180);
g2.setColor(c2);
g2.drawOval(244 + 522*i, 365, 180, 180);
}
for (int i = 0; i < 10; i++) {
g2.setColor(c3);
g2.fillOval(130 + 174*i, 428, 60, 60);
g2.setColor(c3);
g2.drawOval(130 + 174*i, 428, 60, 60);
}
for (int i = 0; i < 25; i++) {
g2.setColor(c4);
g2.fillOval(60 + 87*i, 444, 25, 25);
g2.setColor(c4);
g2.drawOval(60 + 87*i, 444, 25, 25);
}
for (int i = 0; i < 120; i++) {
g2.setColor(c5);
g2.fillOval(circX + 29*i, 450, 12, 12);
g2.setColor(c5);
g2.drawOval(circX + 29*i, 450, 12, 12);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MyTaskToo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Circle());
frame.setSize(windowW, windowH);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Thanks for your time.
This is how I went about this problem, although we had to do it with green circles as opposed to grey circles but it's not that different.
N.B: Sorry for the appealing comments for sometimes trivial things but we get marks for commenting and it is better to be safe than sorry. Maybe they change you some insight into the thought process.
Here is the main method that starts the programme and sets out the window information.
public class Q2Main {
public static void main(String[] args) {
// here we are just setting out the window end putting the circles drawin in Q2Circles into this window.
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(1000, 500);
window.getContentPane().add(new Q2Circles(5));
window.setVisible(true);
}}
This is where the magic happens:
public class Q2Circles extends JPanel {
// this allows the user to specify how many loops of recursion they want the programme to complete before finishing
int recursionsToDo;
public Q2Circles(int recursionMax){
super();
recursionsToDo = recursionMax;
}
/*
this method is automatically called when we run the constructor as it inherits from the JFram superclass. here
we are setting out the size of the circle by getting the size of the window to make it proportional to the rest
of the screen and circles.
we then pass these values into the drawCircle method to draw the circle
*/
public void paintComponent(Graphics g){
Rectangle rectangle = this.getBounds();
int diameter = rectangle.width/3;
int centerPoint = rectangle.width/2;
drawCircle(g, 1, centerPoint, diameter);
}
/*
This method is where the magic of the programme really takes place. first of all we make sure we haven't completed
the necessary recursions. we the set the color by dividing it by the amount of times we have recursed, this will
have the affect of getting darker the more times the method recurses. we then sset the color. finaly we fill the
oval (draw the circle). because we want to move depending on the times it has recursed and size of the previous
we do it based on the size of the elements from the previous call to this method. Getting the right numbers
though was just alot of trial and error.
we then increment the recursion counter so that we know how many times we have recursed and that can then be
used at different points where needed. e.g for setting the color.
each recursive call used the dimension of the other recursive calls to make the whole picture. Although the
first recursive call creates the circles on the right of the screen. the second call draws the circle on the
left of the screen and the last one does the circles in the middle, they all use eachothers values to make it
complete. without one recursive step, more is missing than just what is created by that recursive call on its own.
in all honesty though, there is alot of duplication, like the large middlecircle.
*/
public void drawCircle(Graphics g, int amountOfRecursions, int center, int diameter){
if (amountOfRecursions <= recursionsToDo){
int recursionsCount = amountOfRecursions;
int greenColor = Math.round(225 / (amountOfRecursions));
g.setColor(new Color(0, greenColor, 0));
g.fillOval(center - (diameter/2), 200 - (diameter/2), diameter, diameter);
recursionsCount++;
drawCircle(g, recursionsCount, Math.round(center + diameter), diameter/3);
drawCircle(g, recursionsCount, Math.round(center - diameter), diameter/3);
drawCircle(g, recursionsCount, Math.round(center), diameter/3);
}
}}
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.