Why won't gc.clearRect clear the canvas? - java
I have some code in a MazeUI class that creates a couple of fields in JavaFX for entering the height and width of a Maze to be generated along with a Button and the event for the button. On clicking Generate Maze the code should generate a random maze.
Now this works fine. But the line to clear the canvas after the Maze is first drawn using gc.clearRect(x, y, z, a) doesn't appear to work and Maze's are re-drawn on top of one another on subsequent clicks:
package dojo.maze.ui;
import dojo.maze.generator.MazeGenerator;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.stage.Stage;
public class MazeUI extends Application {
private MazeGenerator generator;
private Integer height = 15;
private Integer width = 15;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Dojo: Solving a Maze");
Group root = new Group();
drawMazeView(root);
primaryStage.setScene(new Scene(root, Color.WHITE));
primaryStage.show();
}
private GraphicsContext initialiseGraphicsContext(Canvas canvas) {
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.BLACK);
gc.fillRect(0,0,600,600);
gc.setStroke(Color.GREEN);
gc.setLineCap( StrokeLineCap.ROUND );
gc.setLineJoin( StrokeLineJoin.ROUND );
gc.setLineWidth(3);
BoxBlur blur = new BoxBlur();
blur.setWidth(1);
blur.setHeight(1);
blur.setIterations(1);
gc.setEffect(blur);
return gc;
}
private void drawMazeView(Group root) {
Canvas canvas = new Canvas(800, 800);
GraphicsContext gc = initialiseGraphicsContext(canvas);
GridPane.setConstraints(canvas, 0, 6);
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(5);
grid.setHgap(5);
Label heightLabel = new Label("Height:");
final TextField heightTextField = new TextField();
HBox hbHeight = new HBox();
hbHeight.getChildren().addAll(heightLabel, heightTextField);
hbHeight.setSpacing(10);
GridPane.setConstraints(hbHeight, 0, 0);
Label widthLabel = new Label("Label:");
final TextField widthTextField = new TextField();
HBox hbWidth = new HBox();
hbWidth.getChildren().addAll(widthLabel, widthTextField);
hbWidth.setSpacing(10);
GridPane.setConstraints(hbWidth, 0, 2);
VBox fieldsBox = new VBox();
fieldsBox.getChildren().addAll(hbHeight, hbWidth);
// Create button that allows you to generate a new maze
Button btn = new Button();
btn.setText("Generate Random Maze");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Button clicked!");
height = Integer.valueOf(heightTextField.getText());
width = Integer.valueOf(widthTextField.getText());
// clear old maze
gc.clearRect(0, 0,
canvas.getHeight(),
canvas.getWidth());
generator = new MazeGenerator(height, width);
drawMaze(gc);
}
});
GridPane.setConstraints(btn, 0, 4);
grid.getChildren().addAll(fieldsBox, btn, canvas);
root.getChildren().add(grid);
}
void drawMaze(GraphicsContext gc) {
int[][] maze = generator.maze();
int xPos = 20,
yPos = 20,
length = 40,
gap = 10;
for (int i = 0; i < width; i++) {
xPos = 20;
// draw the north edge
for (int j = 0; j < height; j++) {
if ((maze[j][i] & 1) == 0) {
gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
}
xPos += length + gap;
System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+ ");
}
System.out.println("+");
xPos = 20;
// draw the west edge
for (int j = 0; j < height; j++) {
if ((maze[j][i] & 8) == 0) {
gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
}
xPos += length + gap;
System.out.print((maze[j][i] & 8) == 0 ? "| " : " ");
}
gc.strokeLine(xPos, yPos, xPos, yPos + length); // vertical
System.out.println("|");
yPos += length + gap;
}
// draw the bottom line
xPos = 20; // reset x pos to western edge
for (int j = 0; j < height; j++) {
gc.strokeLine(xPos, yPos, xPos + length, yPos); // horizontal
System.out.print("+---");
xPos += length + gap;
}
System.out.println("+");
}
public static void main(String[] args) {
launch(args);
}
}
Code for MazeGenerator:
package dojo.maze.generator;
import java.util.Arrays;
import java.util.Collections;
/*
* recursive backtracking algorithm
* shamelessly borrowed from the ruby at
* http://weblog.jamisbuck.org/2010/12/27/maze-generation-recursive-backtracking
*/
public class MazeGenerator {
private final int x;
private final int y;
private final int[][] maze;
public static final int[][] mazeProblemOne = new int[][] {{2,5,2,3,7,3,1,6,7,3,3,5,6,3,5},{4,10,3,5,12,6,3,9,10,3,5,12,8,6,13},{12,6,5,12,12,14,3,1,6,3,9,10,3,9,12},{12,12,12,12,12,12,6,3,9,4,6,7,1,6,9},{14,9,10,9,12,12,12,6,5,12,12,10,5,12,4},{12,2,7,5,12,12,10,9,12,10,13,4,10,9,12},{12,6,9,12,12,12,2,5,10,5,10,11,3,3,13},{12,10,5,12,10,11,3,13,4,10,5,6,3,1,12},{12,6,9,10,5,4,6,9,12,6,9,12,6,3,9},{10,9,6,1,12,10,11,3,9,12,6,13,12,2,5},{6,7,9,6,9,6,3,3,3,9,8,12,12,6,13},{8,12,6,9,6,13,6,3,7,3,3,13,12,12,12},{6,9,10,5,12,12,12,4,10,3,5,8,12,12,8},{14,3,5,12,8,12,10,11,3,5,10,5,12,10,5},{10,1,10,11,3,9,2,3,3,11,1,10,11,3,9}};
public static final int[][] mazeProblemTwo = new int[][] {{2,5,6,5,6,3,1,6,3,3,7,5,2,3,5},{4,10,9,12,14,3,3,9,6,5,12,10,3,3,9},{14,3,3,9,8,6,3,5,12,12,10,3,3,3,5},{12,6,3,3,5,12,4,10,9,10,3,3,3,3,13},{12,12,6,5,12,12,10,3,3,3,5,6,3,3,9},{12,10,9,12,10,9,6,5,6,3,13,10,3,3,5},{10,3,5,12,6,5,12,10,9,4,14,3,3,1,12},{4,6,9,12,12,10,9,6,3,11,13,6,3,3,9},{12,12,2,13,14,3,5,8,6,5,8,10,3,3,5},{12,10,3,9,12,4,12,6,9,12,6,5,6,3,9},{14,7,3,1,10,13,12,12,4,12,12,10,9,6,1},{12,10,3,7,1,12,10,11,9,12,12,2,3,11,5},{12,2,5,12,6,9,2,5,6,9,10,3,3,5,12},{10,5,12,12,12,6,3,13,12,6,7,1,6,9,12},{2,11,9,10,11,9,2,9,10,9,10,3,11,3,9}};
public static final int[][] mazeProblemThree = new int[][] {{2,5,2,3,7,3,3,3,5,6,3,1,6,7,1},{4,10,3,5,12,2,5,6,9,10,3,3,9,14,5},{10,7,5,12,10,5,14,9,6,5,6,3,5,12,12},{6,9,8,10,3,9,12,6,13,12,10,5,12,12,12},{12,6,3,7,1,6,9,12,12,10,3,9,12,8,12},{12,12,4,10,5,10,5,8,14,3,5,2,11,3,13},{12,10,13,4,10,5,10,5,10,5,10,5,6,5,12},{14,1,12,10,5,14,1,12,6,9,4,10,9,12,12},{14,5,10,5,12,10,5,12,12,2,15,3,1,12,12},{8,12,6,9,10,5,12,12,10,3,9,6,3,9,12},{6,9,14,3,3,9,12,10,3,3,3,9,4,6,9},{10,5,12,6,3,3,13,6,3,3,1,6,11,9,4},{6,9,12,10,5,6,11,9,6,3,3,9,6,3,13},{14,5,12,4,12,10,1,6,9,6,5,2,13,4,12},{8,10,11,9,10,3,3,11,3,9,10,3,9,10,9}};
public static final int[][] mazeProblemFour = new int[][] {{2,3,3,5,4,6,7,3,3,5,6,5,6,3,5},{6,3,1,12,12,12,10,3,5,10,9,12,10,5,12},{12,6,3,9,14,9,4,6,9,2,3,11,1,12,12},{14,9,2,3,11,5,12,10,3,5,6,3,3,9,12},{10,5,6,5,2,11,11,5,4,12,12,6,7,1,12},{4,10,9,10,3,5,6,9,12,10,9,8,12,6,13},{14,5,4,6,3,9,12,6,11,5,6,3,9,12,8},{12,10,9,12,4,6,9,10,5,12,14,3,5,10,5},{12,6,5,12,12,12,6,3,9,12,8,6,13,4,12},{14,9,10,9,12,12,10,3,5,10,5,12,10,13,12},{12,2,7,5,10,11,3,3,9,6,9,12,2,9,12},{10,3,9,10,3,3,5,4,6,11,3,9,6,3,13},{6,5,6,7,3,5,12,10,9,6,3,3,9,6,9},{12,10,9,10,5,8,12,6,5,10,5,6,5,10,5},{10,3,3,1,10,3,11,9,10,3,9,8,10,3,9}};
public static final int[][] mazeProblemFive = new int[][] {{2,3,5,6,3,3,7,5,6,3,3,3,7,3,5},{6,5,12,12,6,3,9,8,10,5,4,6,9,4,12},{12,12,12,12,10,3,5,6,5,10,13,10,5,14,9},{12,10,9,10,5,4,10,9,14,1,12,4,12,10,5},{10,5,6,5,10,15,3,1,14,5,14,9,10,5,8},{6,9,12,10,5,8,6,5,8,10,9,6,5,14,5},{10,3,9,4,12,6,9,10,3,3,3,9,12,8,12},{6,3,7,13,12,10,7,5,2,7,7,1,10,3,13},{14,1,12,8,10,5,12,12,6,9,12,6,3,3,9},{8,6,13,6,3,9,12,12,12,2,13,12,6,3,5},{6,9,8,12,4,6,9,12,14,5,8,10,9,4,12},{12,6,3,9,10,9,6,9,8,10,7,5,6,11,9},{12,10,3,3,3,5,14,3,3,5,12,12,10,5,4},{14,1,6,5,6,9,10,3,1,12,12,10,1,10,13},{10,3,9,10,11,3,3,3,3,9,10,3,3,3,9}};
public MazeGenerator(int x, int y) {
this.x = x;
this.y = y;
maze = new int[this.x][this.y];
generateMaze(0, 0);
}
public void display() {
for (int i = 0; i < y; i++) {
// draw the bbc.north edge
for (int j = 0; j < x; j++) {
System.out.print((maze[j][i] & 1) == 0 ? "+---" : "+ ");
}
System.out.println("+");
// draw the west edge
for (int j = 0; j < x; j++) {
System.out.print((maze[j][i] & 8) == 0 ? "| " : " ");
}
System.out.println("|");
}
// draw the bottom line
for (int j = 0; j < x; j++) {
System.out.print("+---");
}
System.out.println("+");
}
private void generateMaze(int cx, int cy) {
DIR[] dirs = DIR.values();
Collections.shuffle(Arrays.asList(dirs));
for (DIR dir : dirs) {
int nx = cx + dir.dx;
int ny = cy + dir.dy;
if (between(nx, x) && between(ny, y)
&& (maze[nx][ny] == 0)) {
maze[cx][cy] |= dir.bit;
maze[nx][ny] |= dir.opposite.bit;
generateMaze(nx, ny);
}
}
}
private static boolean between(int v, int upper) {
return (v >= 0) && (v < upper);
}
public int[][] maze() {
return maze;
}
private enum DIR {
N(1, 0, -1), S(2, 0, 1), E(4, 1, 0), W(8, -1, 0);
private final int bit;
private final int dx;
private final int dy;
private DIR opposite;
// use the static initializer to resolve forward references
static {
N.opposite = S;
S.opposite = N;
E.opposite = W;
W.opposite = E;
}
private DIR(int bit, int dx, int dy) {
this.bit = bit;
this.dx = dx;
this.dy = dy;
}
};
public static void main(String[] args) {
int x = args.length >= 1 ? (Integer.parseInt(args[0])) : 8;
int y = args.length == 2 ? (Integer.parseInt(args[1])) : 8;
MazeGenerator maze = new MazeGenerator(x, y);
maze.display();
}
}
How do I fix the code so that it correctly clears the Maze after each button click? Am I missing something?
Remove the BoxBlur effect before you clear the canvas, then re-apply it. Clearing the canvas simply paints with a transparent color. So the BoxBlur effect will affect that too.
And what jewelsea said. You'd have found it yourself if you'd only reduced the code to a minimum ;-)
For people looking for an answer, another reason why it may not be working is if you set the GraphicsContext.globalBlendMode to something like BlendMode.SCREEN.
Since clearRect() paints the canvas with transparent pixels, a transparent pixel would have no effect in that BlendMode.
Set the gc.globalBlendMode = BlendMode.SRC_OVER right before calling clearRect()
Related
Why are JLabels being painted over higher components in a JLayeredPane?
I have a JLayeredPane that has four layers: JPanel set as a background Grid of JPanels each holding a JLabel Grid of JPanels each holding several JLabels that are only set to visible if the label in the panel below is empty A custom component that is only used to override the paintComponent() method to draw over everything below For some reason if I change the background colour of the labels in layer 3 and then draw to layer 4, the labels in layer 3 are painted over the graphics painted in level 4. I have tried to set ignoreRepaint() on various components as well as playing around with the opacity and code structure but all to no avail. Does anyone know how to prevent this from happening? I won't attach the source code because the project is quite large but I've attached an example that runs as a stand alone program and demonstrates my problem when you hit the "add arrow" button. import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.border.LineBorder; public class GraphicsTest { #SuppressWarnings("serial") class Painter extends JComponent { public Painter(int x, int y) { setBounds(0, 0, x, y); } #Override public void paintComponent(Graphics g) { super.paintComponent(g); } } private static final int CELL_SIZE = 40; private static final int NOTE_SIZE = 20; private JFrame frame; private static JButton test; private static JButton clear; private static JLayeredPane pane = new JLayeredPane(); private static JPanel back = new JPanel(); private static JPanel[][] cellPanels = new JPanel[10][10]; private static JLabel[][] cells = new JLabel[10][10]; private static JPanel[][] notePanels = new JPanel[10][10]; private static JLabel[][][] notes = new JLabel[10][10][4]; private static Painter painter; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { GraphicsTest window = new GraphicsTest(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public GraphicsTest() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setSize(600, 700); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(null); pane.setBounds(50, 50, 500, 500); pane.setLayout(null); frame.getContentPane().add(pane); back.setBounds(0, 0, 500, 500); back.setBackground(Color.BLACK); pane.add(back, new Integer(100)); for (int i = 0; i < 10; i++) { for (int k = 0; k < 10; k++) { String text = ""; if ((i % 2) == 1 && (k % 2) == 1) text = (i + k) + ""; cellPanels[i][k] = new JPanel(); cellPanels[i][k].setBounds(k * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE); cellPanels[i][k].setBackground(Color.WHITE); cellPanels[i][k].setBorder(new LineBorder(Color.BLACK, 1)); cells[i][k] = new JLabel(text); cells[i][k].setBounds(0, 0, CELL_SIZE, CELL_SIZE); cells[i][k].setOpaque(false); cellPanels[i][k].add(cells[i][k]); pane.add(cellPanels[i][k], new Integer(200)); } } boolean display; for (int i = 0; i < 10; i++) { for (int k = 0; k < 10; k++) { if ((i % 2) == 0 && (k % 2) == 0) { display = true; } else { display = false; } notePanels[i][k] = new JPanel(); notePanels[i][k].setBounds(k * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE); notePanels[i][k].setBackground(Color.WHITE); notePanels[i][k].setBorder(new LineBorder(Color.BLACK, 1)); notePanels[i][k].setLayout(null); for (int m = 0; m < 2; m++) { for (int p = 0; p < 2; p++) { notes[i][k][(m * 2) + p] = new JLabel(30 + ""); notes[i][k][(m * 2) + p].setBounds(m * NOTE_SIZE, p * NOTE_SIZE, NOTE_SIZE, NOTE_SIZE); notes[i][k][(m * 2) + p].setOpaque(true); notePanels[i][k].add(notes[i][k][(m * 2) + p]); } } if (display) { notePanels[i][k].setVisible(true); } else { notePanels[i][k].setVisible(false); } pane.add(notePanels[i][k], new Integer(300)); } } painter = new Painter(500, 500); pane.add(painter, new Integer(400)); test = new JButton("Add Arrow"); test.setBounds(50, 600, 100, 25); test.addActionListener(new ActionListener() { #Override public void actionPerformed(ActionEvent arg0) { highlightNotes(); Arrow.drawArrow(painter.getGraphics(), 20, 20, 400, 400, 20, 30, 40, Color.BLACK, Color.GREEN); } }); frame.getContentPane().add(test); clear = new JButton("Clear"); clear.setBounds(175, 600, 100, 25); clear.addActionListener(new ActionListener() { #Override public void actionPerformed(ActionEvent arg0) { painter.repaint(); } }); frame.getContentPane().add(clear); } private static void highlightNotes() { for (int i = 0; i < 10; i++) { for (int k = 0; k < 10; k++) { for (int n = 0; n < 4; n++) { notes[i][k][n].setBackground(Color.BLUE); } } } } static class Arrow { public static void drawArrow(Graphics g, int tailx, int taily, int headx, int heady, int shaftw, int headw, int headh, Color outline, Color fill) { if ((shaftw % 2) == 0) { shaftw--; } if ((headw % 2) == 0) { headw--; } if ((headh % 2) == 0) { headh--; } Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); double length = Math.sqrt((double) (((headx - tailx) * (headx - tailx)) + ((heady - taily) * (heady - taily)))); int tailLength = (int) (length - headw) + 1; double theta = Math.atan2(heady - taily, headx - tailx); Point point1 = new Point(0, -(shaftw / 2)); point1 = getTransPoint(point1, theta); point1.x += tailx; point1.y += taily; Point point2 = new Point(tailLength, -(shaftw / 2)); point2 = getTransPoint(point2, theta); point2.x += tailx; point2.y += taily; Point point3 = new Point(tailLength, -(headw / 2)); point3 = getTransPoint(point3, theta); point3.x += tailx; point3.y += taily; Point point4 = new Point((int) length, 0); point4 = getTransPoint(point4, theta); point4.x += tailx; point4.y += taily; Point point5 = new Point(tailLength, (headw / 2)); point5 = getTransPoint(point5, theta); point5.x += tailx; point5.y += taily; Point point6 = new Point(tailLength, (shaftw / 2)); point6 = getTransPoint(point6, theta); point6.x += tailx; point6.y += taily; Point point7 = new Point(0, (shaftw / 2)); point7 = getTransPoint(point7, theta); point7.x += tailx; point7.y += taily; //Create arrow at tail coordinates passed in Polygon arrow = new Polygon(); arrow.addPoint(point1.x, point1.y); arrow.addPoint(point2.x, point2.y); arrow.addPoint(point3.x, point3.y); arrow.addPoint(point4.x, point4.y); arrow.addPoint(point5.x, point5.y); arrow.addPoint(point6.x, point6.y); arrow.addPoint(point7.x, point7.y); //Draw and fill the arrow g2.setColor(fill); g2.fillPolygon(arrow); g2.setColor(outline); g2.drawPolygon(arrow); } private static Point getTransPoint(Point point, double theta) { int x = (int) ((point.x * Math.cos(theta)) - (point.y * Math.sin(theta))); int y = (int) ((point.y * Math.cos(theta)) + (point.x * Math.sin(theta))); return new Point(x, y); } } }
How to add an image into a hexagon in a hexagonal grid?
I have a problem with a hexagonal grid. I found this code you can see below on Internet, so it's not mine. There are two public classes: hexgame which generates the grid and hexmech which draws and fills every single hexagon. What I'd like to do is basically insert an image into a specific hexagon, but I don't know how to code this and in which part of the classes I should put it. Am I thinking the wrong way? Thank you very much for your help! Hexgame package hex; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class hexgame { private hexgame() { initGame(); createAndShowGUI(); } final static Color COLOURBACK = Color.WHITE; final static Color COLOURCELL = Color.WHITE; final static Color COLOURGRID = Color.BLACK; final static Color COLOURONE = new Color(255,255,255,200); final static Color COLOURONETXT = Color.BLUE; final static Color COLOURTWO = new Color(0,0,0,200); final static Color COLOURTWOTXT = new Color(255,100,255); final static Color COLOURSAFE = Color.WHITE; final static Color COLOURDANGEROUS = Color.LIGHT_GRAY; final static int EMPTY = 0; final static int UNKNOWN = -1; final static int SAFE = 1; final static int DANGEROUS = 2; final static int CLICKED = 3; final static int COLUMN_SIZE = 23; final static int ROW_SIZE = 14; final static int HEXSIZE = 45; final static int BORDERS = 15; int[][] board = new int[COLUMN_SIZE][ROW_SIZE]; void initGame(){ hexmech.setXYasVertex(false); hexmech.setHeight(HEXSIZE); hexmech.setBorders(BORDERS); for (int i=0;i<COLUMN_SIZE;i++) { for (int j=0;j<ROW_SIZE;j++) { board[i][j]=EMPTY; } } board[5][5] = SAFE; board[5][6] = SAFE; board[5][7] = SAFE; board[6][5] = SAFE; board [6][6] = SAFE; board[4][4] = UNKNOWN; } private void createAndShowGUI() { DrawingPanel panel = new DrawingPanel(); JFrame frame = new JFrame("Hex Testing 4"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); Container content = frame.getContentPane(); content.add(panel); frame.setSize(825, 630); frame.setResizable(true); frame.setLocationRelativeTo( null ); frame.setVisible(true); } class DrawingPanel extends JPanel { public DrawingPanel() { setBackground(COLOURBACK); MyMouseListener ml = new MyMouseListener(); addMouseListener(ml); } public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setFont(new Font("TimesRoman", Font.PLAIN, 15)); super.paintComponent(g2); for (int i=0;i<COLUMN_SIZE;i++) { for (int j=0;j<ROW_SIZE;j++) { if (board[i][j] != UNKNOWN) hexmech.drawHex(i,j,g2); } } for (int i=0;i<COLUMN_SIZE;i++) { for (int j=0;j<ROW_SIZE;j++) { if (board[i][j] != UNKNOWN) hexmech.fillHex(i,j,board[i][j],g2); } } } class MyMouseListener extends MouseAdapter { public void mouseClicked(MouseEvent e) { int x = e.getX(); int y = e.getY(); Point p = new Point( hexmech.pxtoHex(e.getX(),e.getY()) ); if (p.x < 0 || p.y < 0 || p.x >= COLUMN_SIZE || p.y >= ROW_SIZE) return; board[p.x][p.y] = CLICKED; repaint(); } } } } Hexmech package hex; import java.awt.*; import javax.swing.*; public class hexmech { #define HEXEAST 0 #define HEXSOUTHEAST 1 #define HEXSOUTHWEST 2 #define HEXWEST 3 #define HEXNORTHWEST 4 #define HEXNORTHEAST 5 public final static boolean orFLAT= true; public final static boolean orPOINT= false; public static boolean ORIENT= orFLAT; public static boolean XYVertex=true; private static int BORDERS=50 private static int s=0; // length of one side private static int t=0; // short side of 30o triangle outside of each hex private static int r=0; // radius of inscribed circle (centre to middle of each side). r= h/2 private static int h=0; // height. Distance between centres of two adjacent hexes. Distance between two opposite sides in a hex. public static void setXYasVertex(boolean b) { XYVertex=b; } public static void setBorders(int b){ BORDERS=b; } public static void setSide(int side) { s=side; t = (int) (s / 2); //t = s sin(30) = (int) CalculateH(s); r = (int) (s * 0.8660254037844); h=2*r; } public static void setHeight(int height) { h = height; r = h/2; // r = radius of inscribed circle s = (int) (h / 1.73205); // s = (h/2)/cos(30)= (h/2) / (sqrt(3)/2) = h / sqrt(3) t = (int) (r / 1.73205); // t = (h/2) tan30 = (h/2) 1/sqrt(3) = h / (2 sqrt(3)) = r / sqrt(3) } public static Polygon hex (int x0, int y0) { int y = y0 + BORDERS; int x = x0 + BORDERS; if (s == 0 || h == 0) { System.out.println("ERROR: size of hex has not been set"); return new Polygon(); } int[] cx,cy; if (XYVertex) cx = new int[] {x,x+s,x+s+t,x+s,x,x-t}; //this is for the top left vertex being at x,y. Which means that some of the hex is cutoff. else cx = new int[] {x+t,x+s+t,x+s+t+t,x+s+t,x+t,x}; //this is for the whole hexagon to be below and to the right of this point cy = new int[] {y,y,y+r,y+r+r,y+r+r,y+r}; return new Polygon(cx,cy,6); } public static void drawHex(int i, int j, Graphics2D g2) { int x = i * (s+t); int y = j * h + (i%2) * h/2; Polygon poly = hex(x,y); g2.setColor(hexgame.COLOURCELL); //g2.fillPolygon(hexmech.hex(x,y)); g2.fillPolygon(poly); g2.setColor(hexgame.COLOURGRID); g2.drawString(String.format("%c;%d", 'A'+i, j+1), x+20, y+40); g2.drawPolygon(poly); } public static void fillHex(int i, int j, int n, Graphics2D g2) { char c='o'; int x = i * (s+t); int y = j * h + (i%2) * h/2; /*if (n < 0) { g2.setColor(hexgame.COLOURONE); g2.fillPolygon(hex(x,y)); g2.setColor(hexgame.COLOURONETXT); c = (char)(-n); g2.drawString(""+c, x+r+BORDERS, y+r+BORDERS+4); //FIXME: handle XYVertex //g2.drawString(x+","+y, x+r+BORDERS, y+r+BORDERS+4); } if (n > 0) { g2.setColor(hexgame.COLOURTWO); g2.fillPolygon(hex(x,y)); g2.setColor(hexgame.COLOURTWOTXT); c = (char)n; if (n==3) { g2.setColor(hexgame.COLOURTWO); g2.fillPolygon(hex(x,y)); g2.setColor(hexgame.COLOURTWOTXT); } } public static Point pxtoHex(int mx, int my) { Point p = new Point(-1,-1); //correction for BORDERS and XYVertex mx -= BORDERS; my -= BORDERS; if (XYVertex) mx += t; int x = (int) (mx / (s+t)); int y = (int) ((my - (x%2)*r)/h); int dx = mx - x*(s+t); int dy = my - y*h; if (my - (x%2)*r < 0) return p; // prevent clicking in the open halfhexes at the top of the screen //System.out.println("dx=" + dx + " dy=" + dy + " > " + dx*r/t + " <"); //even columns if (x%2==0) { if (dy > r) { //bottom half of hexes if (dx * r /t < dy - r) { x--; } } if (dy < r) { //top half of hexes if ((t - dx)*r/t > dy ) { x--; y--; } } } else { // odd columns if (dy > h) { //bottom half of hexes if (dx * r/t < dy - h) { x--; y++; } } if (dy < h) { //top half of hexes //System.out.println("" + (t- dx)*r/t + " " + (dy - r)); if ((t - dx)*r/t > dy - r) { x--; } } } p.x=x; p.y=y; return p; }
In your implementation of paintComponent(), invoke setClip() with a suitable Shape, such as Polygon. You can size and translate the Polygon to match the destination hexagon using the createTransformedShape() method of AffineTransform. Use the coordinates of the polygon's boundary as the basis for the coordinates used in your call to drawImage(). A related example using Ellipse2D is shown here.
Determine if circles intersect
I am working on a project where I have to draw 20 circles with random starting points and random sizes. Then I have to determine if any of the circles intersect. If a circle intersects with another, I have to color that circle green. And if the circle does not intersect with another, the color needs to be red. I have all of the code... I think... but when I run it, I still get some circles that should be green, but are red instead. Here is my code. Any help will be greatly appreciated. import java.awt.Graphics; import javax.swing.JPanel; import java.util.Random; import javax.swing.JFrame; import java.awt.*; public class IntersectingCircles extends JPanel { private int[] xAxis = new int [20]; // array to hold x axis points private int[] yAxis = new int [20]; // array to hold y axis points private int[] radius = new int [20]; // array to hold radius length public static void main (String[] args) { JFrame frame = new JFrame("Random Circles"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.getContentPane().add (new IntersectingCircles()); frame.pack(); frame.setVisible(true); } public IntersectingCircles() { setPreferredSize(new Dimension(1300, 800)); // set window size Random random = new Random(); for (int i = 0; i < 20; i++) { xAxis[i] = random.nextInt(800) + 100; yAxis[i] = random.nextInt(500) + 100; radius[i] = random.nextInt(75) + 10; } } public void paintComponent(Graphics g) { for (int i = 0; i < 20; i++) { int color = 0; for (int h = 0; h < 20; h++) { if(i < h) { double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0; x1 = (xAxis[i] + radius[i]); y1 = (yAxis[i] + radius[i]); x2 = (xAxis[h] + radius[h]); y2 = (yAxis[h] + radius[h]); d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1)))); if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h]))) { color = 0; } else { color = 1; break; } } } if (color == 0) { g.setColor(Color.RED); g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2); } else { g.setColor(Color.GREEN); g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2); } } } }
In the inside for loop, you are only comparing circles of i index with circles with h index, but only those with i < h, because of the condition: for (int h = 0; h < 20; h++) { if(i < h) { ... So, instead you should compare every i circle with every h circle, except if they are the same. You want instead: for (int h = 0; h < 20; h++) { if(i != h) //note the change here { ...
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.
Parabolas within bounds
I have a JPanel 200x200. I trying to create a function that will generate random parabola's with the bounds of the JPanel, with a constraint that the height can't be lower than a 100 (middle of the screen), I basically want to move a shape around these parabolas Here is some code I'm using to get started: Random random = new Random(); int y; int x; int size = random.nextInt(10); int translation = random.nextInt(50); int height = random.nextInt(100) - 200; //between 100 and 200 //Parabola functions : y = ((x/7 - 30))^2 // x and y are coordiates of where the shape is drawn while(y != 200){ y = (float)Math.pow((float)xloc / size - translation ,2) + height; x++; } I've been researching about FlatteningPathIterator but not too sure how to use them. my function y = (float)Math.pow((float)xloc / size - translation ,2) + height;` prints parabola's sometimes outside the bounds, how would i edit it to print parabola's inside the bounds?
There is a Java Swing shape generator for this called Quad2dCurve. The getPathIterator call gives you an enumerator for points on the curve. Here is some example code: import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.util.Random; import javax.swing.*; final class TestCanvas extends JComponent { int size = 200; int n = 10; float[] ph = new float[n]; float[] pw = new float[n]; float[] px = new float[n]; Random gen = new Random(); TestCanvas() { makeRandomParabolas(); setFocusable(true); addKeyListener(new KeyAdapter() { #Override public void keyPressed(KeyEvent e) { makeRandomParabolas(); repaint(); float [] coords = new float [6]; for (int i = 0; i < n; i++) { PathIterator pi = getQuadCurve(i).getPathIterator(null, 0.1); System.out.print(i + ":"); while (!pi.isDone()) { switch (pi.currentSegment(coords)) { case PathIterator.SEG_MOVETO: System.out.print(" move to"); break; case PathIterator.SEG_LINETO: System.out.print(" line to"); break; default: System.out.print(" unexpected"); break; } System.out.println(" (" + coords[0] + "," + coords[1]+")"); pi.next(); } System.out.println(); } } }); } QuadCurve2D.Float getQuadCurve(int i) { return new QuadCurve2D.Float(px[i] - pw[i], size, px[i], size - (2 * ph[i]), px[i] + pw[i], size); } void makeRandomParabolas() { for (int i = 0; i < n; i++) { float x = 0.2f + 0.6f * gen.nextFloat(); px[i] = size * x; pw[i] = size * (Math.min(x, 1 - x) * gen.nextFloat()); ph[i] = size * (0.5f + 0.5f * gen.nextFloat()); } } #Override protected void paintComponent(Graphics g0) { Graphics2D g = (Graphics2D) g0; for (int i = 0; i < n; i++) { g.draw(getQuadCurve(i)); } } } public class Main extends JFrame { public Main() { setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); getContentPane().add(new TestCanvas()); getContentPane().setPreferredSize(new Dimension(200, 200)); pack(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { #Override public void run() { new Main().setVisible(true); } }); } }