I am trying to draw a multiplication table in Java. I can only seem to get the horizontal lines to print out. I'm new to coding and need help knowing where and what line of code I put in my for loop to make it run and look like a complete table.
public static void drawRow(int row, int size) {
g.drawLine(width, 3 + (row - 1) * height, 270, 3 + (row - 1) * height);
for (int col = 1; col <= size; ++col) {
g.drawString(pad(col), col * width, height);
System.out.printf("%4d", row * col);
g.drawString(pad(row * col), width * col, height * row);
}
g.drawLine(width, 3 + (row + 0) * height, 270, 3 + (row + 0) * height);
I tried to do a string above and below my for loop using g.drawLine.
To get an answer, a reproducible example is always a good place to start. I don't know what your code looks like exactly, but I think it might be something like this:
import java.awt.*;
import javax.swing.*;
public class App extends JFrame {
public static void main(String[] args) {
new App();
}
public App() {
super("Multiplication Table");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(640, 480));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row = 1; row <= 10; row++) drawRow(g, row, 10, 25, 25);
}
};
add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void drawRow(Graphics g, int row, int size, int width, int height) {
g.drawLine(width, 3 + (row - 1) * height, 270, 3 + (row - 1) * height);
for (int col = 1; col <= size; ++col) {
g.drawString(pad(col), col * width, height);
System.out.printf("%4d", row * col);
g.drawString(pad(row * col), width * col, height * row);
}
g.drawLine(width, 3 + (row + 0) * height, 270, 3 + (row + 0) * height);
}
public static String pad(Integer value) {
return value.toString();
}
}
What could an answer look like then? Maybe like this:
import java.awt.*;
import javax.swing.*;
public class App extends JFrame {
public static void main(String[] args) {
new App();
}
public App() {
super("Multiplication Table");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(640, 480));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawTable(g, 10, 25, 20);
}
};
add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
/**
* #param g - Graphics from eg paintComponent
* #param size - size of the table (eg 10 for 10x10)
* #param width - width of a cell in pixels
* #param height - height of a cell in pixels
*/
public void drawTable(Graphics g, int size, int width, int height) {
// set the top/left corner of the table
g.translate(20, 20);
// draw horizontal and vertical lines
for(int i = 0; i <= size; i++) {
g.drawLine(i * width, 0, i * width, height * size);
g.drawLine(0, i * height, width * size, i * height);
}
// calculate maximum width (eg width of "100" for size 10)
int maxWdth = g.getFontMetrics().stringWidth("" + size * size);
// draw the multiplications
for(int y = 1; y <= size; y++)
for(int x = 1; x <= size; x++) {
// calculate current width (eg width of "56" for 7x8)
String result = String.valueOf(x * y);
int resWdth = g.getFontMetrics().stringWidth(result);
// to align right, add (maxWdth - resWdth) to drawString x
g.drawString(result, (x - 1) * width + maxWdth - resWdth + 2, y * height - 2);
}
}
Related
I'm using the java.awt graphics class, and I'm trying to make rows and squares.
I can't seem to get the layout of the rows correctly.
I'm trying to code 8 rows with 3 columns each. However, I just get 2 rows with 12 columns.
If somebody can help me to create the outcome that I want, that would be greatly appreciated.
Here's my code:
g.setColor(Color.WHITE);
int x = 70;
int y = 80;
int w = 30;
int h = 35;
for(int row = 0; row < 3; row++) {
for(int col = 0; col < 4; col++) {
g.fillRect( x, y, w, h );
g.fillRect( x, y + h + 20, w, h );
x += w + 15;
}
System.out.println();
}
Here's the output: 2 rows, 12 columns of squares
Beware of how you are updating your position information. For example, you should only be updating the x position in the inner loop and resetting to 0 before entering the inner loop, and the y position should only be updated on each new row.
Alternatively, you could calculate the position directly, based on the row/column index and the row/column height, as demonstrated below.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
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();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
private static int COLUMN_COUNT = 3;
private static int ROW_COUNT = 8;
private static int COLUMN_WIDTH = 30;
private static int ROW_HEIGHT = 35;
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3 * COLUMN_WIDTH, 8 * ROW_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int columnWidth = getWidth() / 3;
int rowHeight = getHeight() / 8;
int x = 0;
int y = 0;
for (int row = 0; row < ROW_COUNT; row++) {
for (int col = 0; col < COLUMN_COUNT ; col++) {
if (col % 2 == 0) {
x = columnWidth * col;
y = rowHeight * row;
g2d.fillRect(x + 2, y + 2, columnWidth - 4, rowHeight - 4);
}
}
}
g2d.dispose();
}
}
}
My partner and I are trying to remake Tetris for our final project of the year in my Computer Science class we currently have a for loop that draws individual rectangles in an overwritten paint method.
private final int spacer = 30;
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
for(int i = getHeight()/2 - (spacer * 10); i < getHeight()/2 + (spacer * 10); i += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += (spacer)) {
g.drawRect(x, i, (spacer), (spacer));
}
}
setForeground(Color.black);
}
The method basically takes the width and height of the window and makes a 10 x 20 grid of boxes that are 30 units, pixels I think, wide.
We'd like to make a Grid.java class that takes in color, the spacer int, and an x and y int. The constructor for Grid.java should draw the exact same thing as the code above using the for loop, but when we tried it gave us a white screen that would not resize with the window.
private final int spacer = 30;
private static Grid[][] arr = new Grid[10][20];
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
int countY = 0;
int countX = 0;
for(int y = getHeight()/2 - (spacer * 10); y < getHeight()/2 + (spacer * 10); y += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += spacer) {
arr[countX][countY] = new Grid(x, y, spacer, g);
countX++;
}
countY++;
}
setForeground(Color.black);
}
*Grid.java Class*
package Tetris_Shapes;
import javax.swing.*;
import java.awt.*;
public class Grid {
private int x;
private int y;
private int side;
private Graphics g;
public Grid(int x, int y, int side, Graphics g) {
// g.drawRect(x, y, spacer, spacer);
this.x = x;
this.y = y;
this.side = side;
this.g = g;
paint(this.g);
}
private void paint(Graphics g) {
g.drawRect(x, y, side, side);
}
}
When we try and run this we get the white box that doesn't resize. My question is does anyone know of a way to get a constructor to draw shapes. Thank you in advance, this is pretty niche so I'm also going to apologize in advance.
I'm having some problems whit drawing a sierpinski carpet, and would apreciate any help.
I was able to define the stoping condition, draw the central rectangle, and recursively, draw the next level of the image, all while keeping count.
It just so happens that I can only draw on the top left side. I'd say I'm confusing variables, but I can't seem to figure it out. Would apreciate any help
This is the part of the code where i'm having problems.
int smallerWidth = newWidth / 3;
int smallerHeight = newHeight / 3;
int sX = 0;
int sY = 0;
if (currentDeep > 1) {
for (int i = 0; i < 3; i++) {
sX = width / 9 + (i * 3 * (width / 9));
sY = height / 9;
g.fillRect(sX, sY, smallerWidth, smallerHeight);
for (int j = 0; j < 3; j++) {
sY = height / 9 + (j * 3 * (height / 9));
g.fillRect(sX, sY, smallerWidth, smallerHeight);
}
}
return 1 + printSquares(g, sX, sY, newWidth, newHeight, currentDeep
- 1);
} else
return 1;
}
This is the full code
https://pastebin.com/WPJ5tG8w
In sum my question is. What should I change/create in order for my program to draw the remaining 7 squares?
The issue with your code is, that you are trying to perform actions for multiple layers of the recursion at once. Normally, in the recursion, you would only paint the Quadrado central, calculate the sizes and coordinates of the smaller rectangles, and call the method recursively. That way you ensure that the recursive calls do not influence the stuff that is already there.
private int printSquares(Graphics g, int xi, int yi, int width, int height, int currentDeep) {
//Quadrado central
int newWidth = width / 3;
int newHeight = height / 3;
int x = (width / 3) + xi;
int y = (height / 3) + yi;
g.fillRect(x, y, newWidth, newHeight);
int sX = 0;
int sY = 0;
if (currentDeep > 1) {
int sum = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//This is the position of each of the small rectangles
sX = i * (width / 3) + xi;
sY = j * (height / 3) + yi;
// Call the method recursively in order to draw the smaller rectangles
sum += printSquares(g, sX, sY, newWidth, newHeight, currentDeep - 1);
}
}
return 1 + sum;
} else
return 1;
}
I hope, this resolves you issue.
I hope this is ok. This is amazing code. I took the liberty to complete this with the original code provided in the question and added the code that fixed it that Illedhar recommended as a added method. Here it is. Thank you for sharing this.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class sierpinskicarpet {
public static Color BACKGROUNDCOLOR = new Color(0, 0, 150);
public static Color FOREGROUNDCOLOR = new Color(255, 180, 0);
// Padrao = 5, alterado
public static int DEEP = 10;
/**
* Build the frame and shows it
*/
public sierpinskicarpet(int deep) {
// the frame and title
JFrame frame = new JFrame();
frame.setTitle("...: Recursive Squares with deep " + deep + " :...");
// Dispose frame on click on close button
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
// set size and center frame on screen
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
// add print area occupying all the frame content area
frame.add(new PrintArea(deep));
// put frame visible
frame.setVisible(true);
}
/**
* Main method
*/
public static void main(String[] args)
{
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
// launch for 1 to DEEP squares frames
for (int i = DEEP; i >= 1; --i) {
// build a new object each time: objects will run
// independently
new sierpinskicarpet(i);
}
}
});
}
}
/**
* Our print area is, in fact, a label extended with the paint squares behavior
*/
class PrintArea extends JLabel {
private static final long serialVersionUID = 1L;
// local deep variable, will keep the registered deep for this the print
// area
int deep;
/**
* constructor
*/
public PrintArea(int deep) {
// call super, that is JLabel, constructor
super();
// set background color and set as well opaque to allow the background
// to be visible
setBackground(sierpinskicarpet.BACKGROUNDCOLOR);
setOpaque(true);
// save the deep
this.deep = deep;
}
/**
* paint method, called by JVM, when it is needed to update the PrintArea
*/
public void paint(Graphics g) {
// call paint from the JLABEL, draws the background of the PrintArea
super.paint(g);
// set drawing color
g.setColor(sierpinskicarpet.FOREGROUNDCOLOR);
// call the amazing print square method
int n = printSquares(g, 0, 0, getWidth(), getHeight(), this.deep);
// put to the world how much squares we printed
System.out.println("Deep = " + deep + ", squares painted: " + n);
}
/**
* Auxiliary method that will to the work. It must print a square with 1/3
* of the length of the frame and at the center and if not the bottom level
* ask to do the same for each of the other 8 square with 1/3 of length but
* called with the new deep
*/
private int printSquares(Graphics g, int xi, int yi, int width, int height, int currentDeep) {
//Quadrado central
int newWidth = width / 3;
int newHeight = height / 3;
int x = (width / 3) + xi;
int y = (height / 3) + yi;
g.fillRect(x, y, newWidth, newHeight);
int sX = 0;
int sY = 0;
if (currentDeep > 1) {
int sum = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//This is the position of each of the small rectangles
sX = i * (width / 3) + xi;
sY = j * (height / 3) + yi;
// Call the method recursively in order to draw the smaller rectangles
sum += printSquares(g, sX, sY, newWidth, newHeight, currentDeep - 1);
}
}
return 1 + sum;
} else
return 1;
}
}
/*
Works Cited:
Recursive changing variables - sierpinski carpet. Stack Overflow. Retrieved May 4, 2022,
from https://stackoverflow.com/questions/49945862/recursive-changing-variables-sierpinski-carpet
*/
I am new with programming. I am not sure how to put an object in the center of a frame. This is how far i got:
public class LetSee extends JPanel {
public void paintComponent(Graphics g) {
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x,y; // Top-left corner of square
for ( row = 0; row < 5; row++ ) {
for ( col = 0; col < 5; col++) {
x = col * 60;
y = row * 60;
if ( (row % 2) == (col % 2) )
g.drawRect(x, y, 60, 60);
else
g.drawRect(x, y, 60, 60);
}
} // end for row
}
}
public class LetSeeFrame extends JFrame {
public LetSeeFrame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1900, 1000);
setVisible(true);
LetSee let = new LetSee();
let.setLayout(new BorderLayout());
add(let,BorderLayout.CENTER);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
LetSeeFrame l = new LetSeeFrame();
}
}
Actually your panel is centered in the frame, but what it draws isn't.
You should make use of the width and the height of the JPanel to center the drawing .
Also put your sizes and numbers into variables, it is less error-prone when you use them several times in your code .
Finally as #MadProgrammer said in the comments :
Don't forget to call super.paintComponent before you doing any custom
painting, strange things will start doing wrong if you don't. Also
paintComponent doesn't need to be public, no one should ever call it
directly
import java.awt.Graphics;
import javax.swing.JPanel;
public class LetSee extends JPanel {
public void paintComponent(final Graphics g) {
super.paintComponent(g);
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x, y; // Top-left corner of square
int maxRows = 5;
int maxCols = 5;
int rectWidth = 60;
int rectHeight = 60;
int maxDrawWidth = rectWidth * maxCols;
int maxDrawHeight = rectHeight * maxRows;
// this is for centering :
int baseX = (getWidth() - maxDrawWidth) / 2;
int baseY = (getHeight() - maxDrawHeight) / 2;
for (row = 0; row < maxRows; row++) {
for (col = 0; col < maxCols; col++) {
x = col * rectWidth;
y = row * rectHeight;
if ((row % 2) == (col % 2)) {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
} else {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
}
}
} // end for row
}
}
currently trying to correct some errors (maybe due to my misunderstanding of some concepts) for a clickable checkerboard applet.
using an array to indicate whether a square of the checkerboard was selected (1 = selected, 0 = not selected) with mouse click listener
add a white border to the square if mouse clicked (selected), without border if clicked again, or stay with a border if I click another square
attention was given to exclude coordinate (0, 0), as I don't want any square to be selected at the beginning, which was the case if I include (0, 0)
Errors:
- the array values changed but the repaint does not behaved as intended, border/ without border
- if I select a square next to another selected square, the selection of the other square disappears
Advices on how I can move forward with this would be much appreciated.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ClickableCheckerboard extends Checkerboard implements MouseListener {
#Override
public void init() {
initSelectionRecord();
addMouseListener(this);
}
private static int
selectedRow, selectedCol, // row and col of checkerboard
x, y; // coordinates of a mouse click
// Selection state of each square of the Checkerboard board.
private static int selectionRecord[][]; // 8 x 8 array (0 to 7, row x col), 0 = not selected, 1 = selected
// Initialise selection state of each square of the Checkerboard board.
public void initSelectionRecord() {
int row, col;
selectionRecord = new int[8][8]; // Allocate memory for the array, otherwise end up with NullPointerException
for (row = 0; row < 8; row++) {
for (col = 0; col < 8; col++) {
selectionRecord[row][col] = 0;
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
selectedRow = getRow(y);
selectedCol = getCol(x);
if (selectedRow != -1 && selectedCol != -1) {
repaint(selectedCol * 20, selectedRow * 20, 19, 19);
repaint(0, 161, 300, 300);
}
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
/**
* Returns the column of the checkerboard for an integer x coordinate.
*
* #param x
* #return col if inside checkerboard, or -1 if outside checkerboard
*/
public int getCol(int x) {
int col = -1;
if (x <= 160 && x != 0) {
col = (int) (x / 20);
}
return col;
}
/**
* Returns the row of the checkerboard for an integer y coordinate.
*
* #param y
* #return row if inside checkerboard, or -1 if outside checkerboard
*/
public int getRow(int y) {
int row = -1;
if (y <= 160 && y != 0) {
row = (int) (y / 20);
}
return row;
}
/**
* Returns the selection state of a square of the checkerboard
*
* #param row
* #param col
* #return i - 1 if selected, 0 if unselected, -1 if not applicable
*/
public static int getSelectionRecord(int row, int col) {
int i = -1;
if (row < 8 && col < 8){
i = selectionRecord[row][col];
}
return i;
}
/**
* Select a square by adding a white border to it, or unselect it by clearing the border
*
* #param row
* #param col
* #param g
*/
public void toggleSelection(int row, int col, Graphics g) {
int evenRow, evenCol, width, height;
evenRow = row % 2;
evenCol = col % 2;
width = 19;
height = 19;
if (getSelectionRecord(row, col) == 0) {
selectionRecord[row][col] = 1;
g.setColor(Color.white);
g.drawRect(col * 20 , row * 20 , width, height);
} else if (getSelectionRecord(row, col) == 1) {
selectionRecord[row][col] = 0;
if (evenRow == 0 && evenCol == 0) {
g.setColor(Color.red);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow != 0 && evenCol != 0) {
g.setColor(Color.red);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow == 0 && evenCol != 0) {
g.setColor(Color.black);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow != 0 && evenCol == 0) {
g.setColor(Color.black);
g.fillRect(col * 20, row * 20, width, height);
}
} else if (getSelectionRecord(row, col) == -1) {
}
}
public void paint(Graphics g) {
super.paint(g);
g.drawString("x is " + x + ". y is " + y + ".", 2, 180);
if (x != 0 && y != 0 && x <=160 && y <= 160) {
if (selectedRow != -1 && selectedCol != -1) {
toggleSelection(selectedRow, selectedCol, g);
}
}
g.drawString("Selection state of toggled square is " + getSelectionRecord(selectedRow, selectedCol), 2, 200);
int i, j;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
g.drawString(getSelectionRecord(i, j) + " ", (2 + j * 20), (220 + i * 20));
}
}
}
}