Nesting for-loop in Order to Create Brick Wall - java

I am new to programming and this is my first time posting to this site. I am currently working on an assignment which will allow a user to input a number between 1 and 20, and then will create a brick wall based upon the number of brick layers the user entered into the JTextField. I was able to create one row, but I don't really understand nesting statements, and all of the examples I've looked at on the web just confuse me more, so I was wondering if someone could possibly help me to better understand nesting for-loops.
//Package List
import java.awt.*;
import java.applet.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
public class Wall extends JApplet implements KeyListener {
//Component declaration
JLabel directions;
JTextField input;
//Variable declaration
int startX = 50;
int startY = 650;
int width = 50;
int height = 20;
int spacing = 2;
//Method declaration
public void init()
{
getContentPane().setBackground(new Color (128, 128, 128));//Changes backround of JApplet to black
//Set JTextField and JLabel
setLayout (new FlowLayout( ));
directions = new JLabel("Enter in any number between 1 and 20 and then press Enter on your keyboard.");
input = new JTextField ( 10 );
add (directions );
add (input);
//Key listener
addKeyListener( this );
setFocusable( true );
}
//Method declaration
public void paint(Graphics g)
{
super.paint (g);
for (int col=1; col<= 8; col++)
{
// for (int row; row<=20; row++)
{ g.setColor (Color.RED);
g.fillRect (startX, startY, 50, 20);
startX = startX + spacing + width;
}
}
}
//Key event methods
public void keyReleased( KeyEvent ke ){}
public void keyTyped (KeyEvent ke ) {}
public void keyPressed ( KeyEvent ke )
{
int key = ke.getKeyCode ( );
if (key == KeyEvent.VK_ENTER)
{
}
}

You need to calculate the x/y position of the brick based on the current row/col. Now, you could simply initialise these values at the start of each loop and increment as required, or you could use a little maths...
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class AnotherBrickInTheWall extends JApplet {
//Component declaration
JLabel directions;
JTextField input;
//Variable declaration
int startX = 0;
int startY = 50;
int width = 50;
int height = 20;
int spacing = 2;
//Method declaration
public void init() {
getContentPane().setBackground(new Color(128, 128, 128));//Changes backround of JApplet to black
//Set JTextField and JLabel
setLayout(new FlowLayout());
directions = new JLabel("Enter in any number between 1 and 20 and then press Enter on your keyboard.");
input = new JTextField(10);
add(directions);
add(input);
}
//Method declaration
#Override
public void paint(Graphics g) {
super.paint(g);
for (int row = 0; row < 8; row++) {
int y = startY + (row * (height + spacing));
for (int col = 0; col < 8; col++) {
int x = startX + (col * (width + spacing));
System.out.println(x + "x" + y);
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
}
}
}
Now, you should never paint on a component which has components added to, this will cause the painting to appear over the top of the components and end up with all sorts of painting issues.
Instead, create a custom component, extending from something like JPanel and override it's paintComponent method instead and place your custom painting here.
You could then add your controls another JPanel and using a BorderLayout on your applet, add these two panels, the fields in the NORTH position and wall in the CENTER position
Updated
If you wanted to get "really" fancy, you could even adjust the x position based on the current row, for example...
int xOffset = 0;
for (int row = 0; row < 8; row++) {
int y = startY + (row * (height + spacing));
if (row % 2 == 0) {
xOffset = width / 2;
} else {
xOffset = 0;
}
for (int col = 0; col < 8; col++) {
int x = xOffset + (startX + (col * (width + spacing)));
System.out.println(x + "x" + y);
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
}
Also, JTextField is has an ActionListener which is triggered when the field is actioned, typically by the user pressing Enter. This means that you shouldn't need the KeyListener.
See How to Use Text Fields for more details.

int x=num //1-20
int step=num/8;
int last_row=num%8;
for(int j=1;j<=step;j++){
int nos=8;
if(j == step && last_step ! = 0)
nos = last_step;
for (int col=1; col<= nos; col++)
{
g.setColor (Color.RED);
g.fillRect (startX, startY, 50, 20);
startX = startX + spacing + width;
startY = startY*j;
}
}
Try this.

Related

Swing draw string centeralised

I have to draw n + 1 amount of circles horizontally and vertically in a GUI. Which I have successfully done as shown below. With this, a 2D array of strings will be printed between them, centralised.
How it currently stands
Now I want to draw numbers in a "square" of the dots.
How I want the final result
for (int i = 0; i < width; i++) {
for (int j = 0; j < width; j++) {
canvas.drawCircle( (j + 1) * 125, (i + 1) * 125, 15, Color.white);
}
}
for (int r = 0; r < size; r++) {
for (int c = 0; c < size; c++) {
canvas.drawString(events[r][c], (r + 1) * 150, (c + 1) * 150, Color.green );
}
}
Width in this case is 4, so basically (n-1) dots/circles in the picture.
Size is 3 which is just the length of the 2d array, as there are 4 circles in this case there will be 3 numbers between each one
Events is the 2D array with the data containing the numbers
The drawCircle method's signature is
(x, y, radius, color)
The drawString method's signature is
(text, x, y color)
I believe part of the problem is also the drawing of circles. Basically I think it has to do with the rubbish formula I have for determining the x, y coords for both circles and the text. Any help is appreciated, thank you.
Provided is some code which I believe does what you want. Some of the constants may be tweaked to fit your final requirements. I used a 2D array of numbers and converted to strings during paint. It also allows for the following:
Changing the ball diameter or number of balls will still provide a
correct graph (although it will change its location within the
panel).
The String numbers track along with the size of the balls
Anti-aliasing was turned on to smooth out the graphics.
FontMetrics was used to fine tune the location of the numbers.
One final note: Because this is not resource intensive, the coordinates are calculated within the paintComponent method. A more optimum solution would be to adopt the Flyweight design pattern and precalculate as much as possible before entering paintComponent.
import java.awt.*;
import javax.swing.*;
public class SwingMain extends JPanel {
final static int WIDTH = 700;
final static int HEIGHT = 700;
final static int SEPARATION = 100;
final static int DIAMETER = 25;
final static int NBALLS = 4;
final static int XSTART = WIDTH / (NBALLS + 2);
final static int YSTART = HEIGHT / (NBALLS + 2);
JFrame frame = new JFrame();
int[][] numbers = new int[NBALLS - 1][NBALLS - 1];
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SwingMain().start());
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame.add(this);
setBackground(Color.RED);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// populate numbers in 2D array.
for (int r = 0; r < NBALLS - 1; r++) {
for (int c = 0; c < NBALLS - 1; c++) {
numbers[r][c] = r * (NBALLS - 1) + c + 1;
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// Allow smoothing of the graphics.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.white);
// Iterating by the number of balls is more consistent than
// by x and y due to round of errors.
int y = YSTART;
for (int r = 0; r < NBALLS; r++) {
int x = XSTART;
for (int c = 0; c < NBALLS; c++) {
g2d.fillOval(x, y, DIAMETER, DIAMETER);
x += SEPARATION;
}
y += SEPARATION;
}
// This is the same as above except that the start begins
// halfway between the first row and column
// have the size of the font track with the diameter of the balls
g2d.setFont(new Font("ARIAL", Font.BOLD, DIAMETER));
FontMetrics fm = g2d.getFontMetrics();
y = YSTART + SEPARATION / 2;
for (int r = 0; r < NBALLS - 1; r++) {
int x = XSTART + SEPARATION / 2;
for (int c = 0; c < NBALLS - 1; c++) {
String number = Integer.toString(numbers[r][c]);
// Do some final position adjustment with the font metrics to
// center the number
int strWidth = fm.stringWidth(number);
int strHeight = fm.getAscent();
g2d.drawString(number,
x - strWidth / 2 + DIAMETER / 2,
y + strHeight);
x += SEPARATION;
}
y += SEPARATION;
}
}
}
You could store the coordinates of the circles in a 2D array as well, and use that to find the location of the strings. One thing to note is that the drawCircle method for some reason wont draw the circle with the given center (the coordinates you give will be the top left corner actually).
Point[][] circleCoords = new Point[width][width]; //suppose Point class has x and y coords
for (int i = 0; i < width; i++) {
for (int j = 0; j < width; j++) {
//the -15 actually centers the circle to the coordianates
circleCoords[i][j] = new Point((j + 1) * 125 - 15, (i + 1) * 125 -15);
canvas.drawCircle(circleCoords[i][j].x , circleCoords[i][j].y, 15, Color.white);
}
}
for (int r = 0; r < width-1; r++) {
for (int c = 0; c < width-1; c++) {
//calculate coords from circleCoords array: halfway between them
int xCoord = (circleCoords[r][c].x + circleCoords[r+1][c].x)/2;
int yCoord = (circleCoords[r][c].y + circleCoords[r][c+1].y)/2;
//wont be out of bounds, becouse this runs to width-1
canvas.drawString(events[r][c], xCoord, yCoord, Color.green );
}
}
This still wont actually be perfectly centered, because the drawString will use the coordinates for top left point as well, and not centerpoint. Maybe I miscalculated something, but this should give you the idea: instead of calculating the coordinates independently, re-use the circle coordinates.
Consider a class that represents a single square. The value is represented by a JLabel which is placed at the bottom using straight-forward layout manager (BorderLayout in this example). You can change or manipulate the layout manager to change to position of the JLabel.
class Square extends JPanel{
private static int WIDTH = 100, HEIGHT = 100, DAIMETER = 30, GAP = 5;
private final JLabel label;
Square(int value) {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setLayout(new BorderLayout());
setBackground(Color.red);
setOpaque(true);
label = new JLabel(String.valueOf(value), JLabel.RIGHT);
label.setForeground (Color.white);
Border margin = new EmptyBorder(GAP,GAP,GAP,2*GAP); //top left bottom right
label.setBorder(margin);
add(label, BorderLayout.PAGE_END);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.white);
g2d.fillOval(WIDTH/2 - DAIMETER/2, HEIGHT/2-DAIMETER/2, DAIMETER, DAIMETER);
}
}
Now add 16 instances of this Square to panel representing a board. Its layout manager is set to GridLayout:
class Board extends JPanel{
private static int ROWS = 4, COLS = 4;
Board(){
setLayout(new GridLayout(ROWS, COLS));
for(int index = 0; index < ROWS * COLS; index ++){
add(new Square(index)); //index is used as value for demonstration purposes
}
}
}
Putting it all together (this is a one-file mcve. Copy paste the entire code into SwingMain.java and run )
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
public class SwingMain {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400,250);
frame.add(new Board());
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
class Board extends JPanel{
private static int ROWS = 4, COLS = 4;
Board(){
setLayout(new GridLayout(ROWS, COLS));
for(int index = 0; index < ROWS * COLS; index ++){
add(new Square(index)); //index is used as value for demonstration purposes
}
}
}
class Square extends JPanel{
private static int WIDTH = 100, HEIGHT = 100, DAIMETER = 30, GAP = 5;
private final JLabel label;
Square(int value) {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setLayout(new BorderLayout());
setBackground(Color.red);
setOpaque(true);
label = new JLabel(String.valueOf(value), JLabel.RIGHT);
label.setForeground (Color.white);
Border margin = new EmptyBorder(GAP,GAP,GAP,2*GAP); //top left bottom right
label.setBorder(margin);
add(label, BorderLayout.PAGE_END);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.white);
g2d.fillOval(WIDTH/2 - DAIMETER/2, HEIGHT/2-DAIMETER/2, DAIMETER, DAIMETER);
}
}

Matrix square brackets

I'm using Java Swing and I need to display a matrix with square brackets (normal square bracket like the one we use in math that spans more than one line), the matrix size is not fixed, it depends on the input.
Here is the code I'm using to display the matrix:
public static void printMatrix(String[][] matrix) {
String output = "";
for (int x = 0; x < matrix.length; x++) {
output += Arrays.toString(matrix[x]) + "\n";
}
JOptionPane.showMessageDialog(null, output, "Matrix",
JOptionPane.INFORMATION_MESSAGE);
}
The output:
But I need to have one big connected square bracket as follows:
So I'm searching on how to do this and I found this link https://docs.oracle.com/javase/tutorial/uiswing/components/border.html but it doesn't contain the brackets that I need and also found this https://team.mumie.net/mumie/mathletfactory_lib_apidocs/net/mumie/mathletfactory/display/noc/matrix/MatrixBorder.html#MatrixBorder%28java.awt.Component,%20int%29 but I didn't find any examples on how to use it.
Based on nIcE cOw's answer on one of my above comments, you need to create your own CustomBorder class that extends AbstractBorder and override its paintBorder() method to draw each part of the brackets.
In this case I divided this task in 3 parts, the top / bottom / left & right part of both brackets.
The internalGap variable is the space that should be between the content and the border
Here are some screenshots of how the output looks like:
With 2, 6 and 10 elements
The code that produces the above outputs is:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.AbstractBorder;
public class EquationMatrixBorder {
private JPanel pane;
private CustomBorder customBorder;
private static final int ROWS_AND_COLS = 1;
private void displayGUI() {
JFrame frame = new JFrame("Custom Border Example");
customBorder = new CustomBorder(Color.RED, 15, 10);
pane = new JPanel();
pane.setLayout(new GridLayout(ROWS_AND_COLS, ROWS_AND_COLS, 15, 15));
//Used to fill the grid, not relevant to question
Random random = new Random();
for (int i = 0; i < ROWS_AND_COLS; i++) {
for (int j = 0; j < ROWS_AND_COLS; j++) {
int r = 0;
if (j % 2 == 0) {
r = random.nextInt(2);
} else {
r = random.nextInt(2) - 1;
}
pane.add(new JLabel(String.valueOf(r)));
}
}
pane.setBorder(customBorder);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new EquationMatrixBorder().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class CustomBorder extends AbstractBorder {
private Color color;
private int gap;
private int bracketsTopAndBottom = 10;
private int internalGap;
public CustomBorder(Color color, int gap, int internalGap) {
this.color = color;
this.gap = gap;
this.internalGap = internalGap;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = null;
if (g instanceof Graphics2D) {
g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.setStroke(new BasicStroke(3));
//top part of brackets
g2d.drawLine(x + gap, y + gap, x + gap + bracketsTopAndBottom, (y + gap));
g2d.drawLine(width - x - gap - bracketsTopAndBottom, y + gap, width - gap - x, (y + gap));
//bottom part of brackets
g2d.drawLine(x + gap, height - gap, x + gap + bracketsTopAndBottom, height - gap);
g2d.drawLine(width - x - gap - bracketsTopAndBottom, height - gap, width - gap - x, height - gap);
//left and right part of brackets
g2d.drawLine(x + gap, y + gap, x + gap, height - gap);
g2d.drawLine(width - x - gap, y + gap, width - x - gap, height - gap);
}
}
#Override
public Insets getBorderInsets(Component c) {
return getBorderInsets(c, new Insets(gap, gap, gap, gap));
}
#Override
public Insets getBorderInsets(Component c, Insets insets) {
insets.left = insets.top = insets.right = insets.bottom = gap + internalGap;
return insets;
}
}
Note
I haven't done rows and cols numbers shown in desired output of OP, I'm leaving that out as this question is only related to the square brackets

Inaccurate grid's cells coordinates

Using swing and awt i've created a grid. The user can click over any empty cell
of the grid, marking it as a red cell. The grid is composed by 20 x 20 cells, 32 pixels each.
When the user clicks over a cell, i get the x and y coordinates of the mouse click and i perform the following calculation to find out which is the selected
cell:
int mouseX = e.getX();
int mouseY = e.getY();
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
The problem is that row and col get inaccurate (wrong) when i click near the edges of a cell (right border or bottom border), resulting in the marking of the next cell (cell to the right or cell to the bottom) and not in the marking of the correct one that i'm clicking over.
The more i get closest to the right/bottom borders of the grid, the more the accuracy is bad.
This is how i draw the grid:
public class MainPanel extends JPanel {
// reference to the model
private Model model;
public MainPanel() {
setPreferredSize(new Dimension(660, 660));
// retrieve the model
model = Controller.getController().getModel();
// draw
repaint();
// listen to mouse clicks
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);
// get the row and column clicked
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
if(row > Model.BOARD_SIZE - 1 || col > Model.BOARD_SIZE - 1) { // avoid out of bounds
return;
}
System.out.println("row: " + row + " col: " + col);
Controller.getController().getModel().setTarget(col, row);
repaint();
}
});
}
/**
* Custom painting codes on this JPanel
* Called by repaint()
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // fills background
setBackground(Color.WHITE); // sets background color
// draw the tiles
Node[][] nodes = model.getBoard();
for(int i = 0; i < Model.BOARD_SIZE; i++) {
for(int j = 0; j < Model.BOARD_SIZE; j++) {
if(nodes[i][j].getNodeType() == NodeType.OBSTACLE) {
g.setColor(Color.BLACK);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else if(nodes[i][j].getNodeType() == NodeType.SOURCE) {
g.setColor(Color.GREEN);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else if(nodes[i][j].getNodeType() == NodeType.TARGET) {
g.setColor(Color.RED);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else {
g.setColor(Color.BLACK);
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
}
}
}
}
Link to the runnable:
https://www.dropbox.com/s/bqoimipp7i1f39s/GridExample.jar?dl=0
Your paint code is wrong, basically...
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
is increasing the size of each cell by a factor of the row/cell been drawn, for example...
The green line is calculated by using g.drawRect(0, 0, BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE);, which should be the visible area of your grid, but you're drawing beyond it.
Instead, if I use...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class MainPanel extends JPanel {
public static final int NODE_SIZE = 32;
public static final int BOARD_SIZE = 8;
private int row, col = -1;
public MainPanel() {
// listen to mouse clicks
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);
// get the row and column clicked
int row = mouseY / NODE_SIZE;
int col = mouseX / NODE_SIZE;
if (row > BOARD_SIZE - 1 || col > BOARD_SIZE - 1) { // avoid out of bounds
return;
}
System.out.println("row: " + row + " col: " + col);
repaint();
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
row = mouseY / NODE_SIZE;
col = mouseX / NODE_SIZE;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE);
}
/**
* Custom painting codes on this JPanel Called by repaint()
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // fills background
setBackground(Color.WHITE); // sets background color
g.setColor(Color.GREEN);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (row == j && col == i) {
g.setColor(Color.RED);
g.fillRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
}
g.setColor(Color.BLACK);
g.drawRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
}
}
}
}
}
It becomes decidedly more accurate..
Another idea might be to use Rectangle to define each cell of the grid, that way you could just use Rectangle#contains to test if the mouse is within any given cell bounds...as an idea
Seeing this code:
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
In combination with this code:
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
is suspicious, your drawing your rectangles on screen with a size of i + Model.NODE_SIZE * i - so the size of rectangles on screen are offset by 1 for every preceding rectangle. This offset would compound making your underlying "detection" of the rectangle you selected slowly get worse the further bottom right on the screen you click.
I suspect if you change your code to read
g.fillRect(Model.NODE_SIZE * i, Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
It will work as intended.

Java Swing: Issue painting a grid

The program is supposed to run a cellular automata simulation (think Conway's game of life) on a painted grid and has a start/pause button to, well, start/pause the simulation, which runs on a 1 second interval. As far as I can tell, everything else except for painting the grid (processing, rest of the GUI), works fine.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ConcurrentModificationException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CA_DriverV2 extends JFrame{
private static final Color white = Color.WHITE, black = Color.BLACK;
private Board board;
private JButton start_pause;
public CA_DriverV2(){
board = new Board();
board.setBackground(white);
start_pause = new JButton("Start");
start_pause.addActionListener(board);
this.add(board, BorderLayout.NORTH);
this.add(start_pause, BorderLayout.SOUTH);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300, 300);
this.setVisible(true);
}
public static void main(String args[]){
new CA_DriverV2();
}
private class Board extends JPanel implements ActionListener{
private final Dimension DEFAULT_SIZE = new Dimension(5, 5);
private final int DEFAULT_CELL = 10, DEFAULT_INTERVAL = 1000, DEFAULT_RATIO = 60;
private Dimension board_size;
private int cell_size, interval, fill_ratio;
private boolean run;
private Timer timer;
private Color[][] grid;
public Board(){
board_size = DEFAULT_SIZE;
cell_size = DEFAULT_CELL;
interval = DEFAULT_INTERVAL;
fill_ratio = DEFAULT_RATIO;
run = false;
//Initialize grid with random values
//NOTE: Add JOptionPane for option to define fill rate and board size?
//ALT: Have a resize(int h, int w) method to resize grid when needed.
//ALT: Have refill(int r) method to restart with different fill ratio.
grid = new Color[board_size.height][board_size.width];
for (int h = 0; h < board_size.height; h++)
for (int w = 0; w < board_size.width; w++){
int r = (int)(Math.random() * 100);
if (r >= fill_ratio)
grid[h][w] = black;
else grid[h][w] = white;
}
timer = new Timer(interval, this);
}
#Override
public Dimension getPreferredSize(){
return new Dimension(board_size.height, board_size.width);
}
#Override
public void paintComponent(Graphics g){
for (int h = 0; h < board_size.height; h++)
for (int w = 0; w < board_size.width; w++){
try{
if (grid[h][w] == black)
g.setColor(black);
else g.setColor(white);
g.fillRect(h * cell_size, w * cell_size, cell_size, cell_size);
} catch (ConcurrentModificationException cme){}
}
}
public void actionPerformed(ActionEvent e) {
//Timer tick processing
if (e.getSource().equals(timer)){
repaint();
Color[][] newGrid = new Color[board_size.height][board_size.width];
for (int h = 1; h < board_size.height; h++)
for (int w = 1; w < board_size.height; w++) {
int surrounding = 0;
//Count black neighbors
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++){
if(i != 0 && j != 0){
try{
if(grid[h + i][w + j] == black)
surrounding++;
} catch(ArrayIndexOutOfBoundsException ae){}
}
}
//Generate next iteration
if (surrounding > 5 || surrounding < 2)
newGrid[h][w] = black;
else newGrid[h][w] = white;
}
for (int h = 1; h < board_size.height; h++){
for (int w = 1; w < board_size.height; w++){
grid[h][w] = newGrid[h][w];
System.out.print(grid[h][w] + " ");
}
System.out.println();
}
System.out.println();
}
//Start-Pause button processing
else if(e.getSource().equals(start_pause)){
if(run){
timer.stop();
start_pause.setText("Pause");
}
else {
timer.restart();
start_pause.setText("Start");
}
run = !run;
}
}
}
}
It prints something at the very top, which looks like a sliver of the initial grid overlayed by a sliver of the button, and the rest is the default grey.
Your board Board variable is added BorderLayout.NORTH not BorderLayout.CENTER, so it only fills the top 5 pixels.
And as per my comment, you should never have code like this in your program:
catch(ArrayIndexOutOfBoundsException ae){}
Not only should you not ignore exceptions, but you shouldn't even catch this type of exceptions. Instead create your for loops with a little care so that they can handle the edges.
Also, don't forget to call the super.paintComponent(g) method in your class's override.

Java draw stairs using drawRect and using inputField for more stairs

I'm a beginner whit Java experience so I hope you can help me.
I want to read the number of steps from a JTextfield. But how can you make the stairs variable?
Graphics g = textP.getGraphics();
int x = 5;
int y = 20;
int width = 10;
int height = 10;
For loop 1 - whil give a drawRect of 6 pieces
for (int i = 0; i < 6; i++) {
g.drawRect(x, y * i, width, height);
}
For loop 2 - whil give a drawRect of 5 pieces
for (int i = 1; i < 6; i++) {
g.drawRect(x + 15, y * i, width, height);
}
For loop 3 - whil give a drawRect of 4 pieces
for (int i = 2; i < 6; i++) {
g.drawRect(x + 30, y * i, width, height);
}
For loop 4 - whil give a drawRect of 3 pieces
for (int i = 3; i < 6; i++) {
g.drawRect(x + 45, y * i, width, height);
}
For loop 5 - whil give a drawRect of 2 pieces
for (int i = 4; i < 6; i++) {
g.drawRect(x + 60, y * i, width, height);
}
For loop 6 - whil give a drawRect of 1 pieces
for (int i = 5; i < 6; i++) {
g.drawRect(x + 75, y * i, width, height);
}
Output (must by an rect ipv *):
*
**
***
****
*****
******
You can do it this way.
JTextField stairs = new JTextField("Enter no. of Stairs");
String noOfStairsStr = stairs.getText();
int noOfStairs = Integer.parseInt(noOfStairsStr);
...
for (int i = 0; i < noOfStairs; i++) { // Use that in the for loop.
Are you expecting something like this
for (int i = 0,k=15; i < 6; i++) {
g.drawRect( ( x+(i*k) ), y * i, width, height);
}
A Graphic environment is complex thing. No longer do you have the safety of fixed character width and heights, now you need to start dealing with a wider range of environmental factors (such as the width and height of the area you have to paint in...)
To get start I would suggest you take a look at
Creating a GUI with Swing
Performing custom painting
2D Graphics
To cover the basics.
In order to paint steps, we need to know (at least) three things.
The number of steps to be painted...
The width of each step
The height of each step.
This example calculates the width and height of the steps as a factor of the width and height of the container it's painting on.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleSteps {
public static void main(String[] args) {
new SimpleSteps();
}
public SimpleSteps() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField steps;
private StairPane stairPane;
public TestPane() {
setLayout(new BorderLayout());
JPanel options = new JPanel();
steps = new JTextField(10);
JButton create = new JButton("Create");
stairPane = new StairPane();
options.add(new JLabel("Step count: "));
options.add(steps);
options.add(create);
add(stairPane);
add(options, BorderLayout.SOUTH);
create.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String value = steps.getText();
try {
int stepCount = Integer.parseInt(value);
stairPane.setStepCount(stepCount);
} catch (NumberFormatException exp) {
JOptionPane.showMessageDialog(TestPane.this, value + " is not a valid step count", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
}
}
public class StairPane extends JPanel {
private int stepCount = 0;
public StairPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (stepCount > 0) {
Graphics g2d = (Graphics2D) g.create();
int stepHeight = getHeight() / stepCount;
int stepWidth = getWidth() / stepCount;
for (int step = stepCount; step != 0; step--) {
int width = stepWidth * step;
int y = (stepHeight * step) - stepHeight;
g2d.fillRect(0, y, width, stepHeight);
}
g2d.dispose();
}
}
private void setStepCount(int stepCount) {
this.stepCount = stepCount;
repaint();
}
}
}

Categories