Why are JLabels being painted over higher components in a JLayeredPane? - java
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);
}
}
}
Related
Modify color array java
Attatched are 2 methods from code that prints out a gird of 25 boxes in jframe and when you click the space bar the boxes fill up one by one with random colors. I need to modify the code so the first 13 boxes show up in shades of red and the next 12 show up only in shades of blue. Also, I need to change the background color to a random color. Thanks. public void setColor() { int r = (int) (Math.random()*256); int g = (int) (Math.random()*256); int b = (int) (Math.random()*256); myColors[clicked] = new Color(r,g,b); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.black); counter = 0; for (int x = 0; x < myFloor.length; x++) { for (int y = 0; y < myFloor[0].length; y++) { if (myColors[counter] != null) { for (int i = 0; i < counter+1; i++) { setColor(); g2.setColor(myColors[i]); g2.fill(myFloor[x][y]); } } else { g2.setColor(Color.BLACK); g2.draw(myFloor[x][y]); } counter++; } } } I need to modify the code so the first 13 boxes show up in shades of red and the next 12 show up only in shades of blue. Also, I need to change the background color to a random color. Thanks.
You could... Use a "color blending" algorithm, which could blend a range of colors together. The following example basically constructs a color range of dark to light red, light blue to dark blue, split over a normalised range of 0-51% and 52-100% This has a neat side effect of filling the first 13 squares with shades of red and the last 12 with shades of blue. import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.text.NumberFormat; 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 class TestPane extends JPanel { private int cols = 5; private int rows = 5; private int cellSize = 50; private ColorGradient colorGradient; public TestPane() { colorGradient = new ColorGradient( new float[]{0f, 0.51f, 0.52f, 1f}, new Color[]{Color.RED.darker(), Color.RED.brighter(), Color.BLUE.brighter(), Color.BLUE.darker()} ); } #Override public Dimension getPreferredSize() { return new Dimension(cols * cellSize, rows * cellSize); } #Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Color borderColor = new Color(0, 0, 0, 64); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { float progress = ((row * rows) + col) / (float)(rows * cols); g2d.setColor(colorGradient.colorAt(progress)); g2d.fillRect(col * cellSize, row * cellSize, cellSize, cellSize); g2d.setColor(borderColor); g2d.drawRect(col * cellSize, row * cellSize, cellSize, cellSize); } } g2d.dispose(); } } public class ColorGradient { private float[] fractions; private Color[] colors; public ColorGradient(float[] fractions, Color[] colors) { this.fractions = fractions; this.colors = colors; } public Color colorAt(float progress) { Color color = null; if (fractions != null) { if (colors != null) { if (fractions.length == colors.length) { int[] indicies = getFractionIndicies(progress); float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]}; Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]}; float max = range[1] - range[0]; float value = progress - range[0]; float weight = value / max; color = blend(colorRange[0], colorRange[1], 1f - weight); } else { throw new IllegalArgumentException("Fractions and colours must have equal number of elements"); } } else { throw new IllegalArgumentException("Colours can't be null"); } } else { throw new IllegalArgumentException("Fractions can't be null"); } return color; } protected int[] getFractionIndicies(float progress) { int[] range = new int[2]; int startPoint = 0; while (startPoint < fractions.length && fractions[startPoint] <= progress) { startPoint++; } if (startPoint >= fractions.length) { startPoint = fractions.length - 1; } range[0] = startPoint - 1; range[1] = startPoint; return range; } protected Color blend(Color color1, Color color2, double ratio) { float r = (float) ratio; float ir = (float) 1.0 - r; float rgb1[] = new float[3]; float rgb2[] = new float[3]; color1.getColorComponents(rgb1); color2.getColorComponents(rgb2); float red = rgb1[0] * r + rgb2[0] * ir; float green = rgb1[1] * r + rgb2[1] * ir; float blue = rgb1[2] * r + rgb2[2] * ir; if (red < 0) { red = 0; } else if (red > 255) { red = 255; } if (green < 0) { green = 0; } else if (green > 255) { green = 255; } if (blue < 0) { blue = 0; } else if (blue > 255) { blue = 255; } Color color = null; try { color = new Color(red, green, blue); } catch (IllegalArgumentException exp) { NumberFormat nf = NumberFormat.getNumberInstance(); System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue)); exp.printStackTrace(); } return color; } } } Oh, and if you want to generate a random color, you could simply use something like... Random rnd = new Random(); Color color = new Color(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)); You could... Define the red and blue color bands separately, and then, based on the cell index, decide which band you're going to use. This provides more "absolute" control over the decision making process. For example, the following index allows the cells between 0-12 inclusively to draw colors from the red band and 13-24 from blue band. import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.text.NumberFormat; 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 class Range { private int lower; private int upper; public Range(int lower, int upper) { this.lower = lower; this.upper = upper; } public int getLower() { return lower; } public int getUpper() { return upper; } public boolean contains(int value) { return value >= getLower() && value <= getUpper(); } public int getDistance() { return getUpper() - getLower(); } public float normalised(int value) { return (value - getLower()) / (float)getDistance(); } } public class TestPane extends JPanel { private int cols = 5; private int rows = 5; private int cellSize = 50; private ColorBand redColorBand; private ColorBand blueColorBand; private Range redRange = new Range(0, 12); private Range blueRange = new Range(13, 24); public TestPane() { redColorBand = new ColorBand( new float[]{0f, 1f}, new Color[]{Color.RED.darker(), Color.RED.brighter()} ); blueColorBand = new ColorBand( new float[]{0f, 1f}, new Color[]{Color.BLUE.brighter(), Color.BLUE.darker()} ); } #Override public Dimension getPreferredSize() { return new Dimension(cols * cellSize, rows * cellSize); } protected Color colorForSqaure(int index) { if (redRange.contains(index)) { return redColorBand.colorAt(redRange.normalised(index)); } else if (blueRange.contains(index)) { return blueColorBand.colorAt(blueRange.normalised(index)); } return Color.BLACK; } #Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Color borderColor = new Color(0, 0, 0, 64); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { g2d.setColor(colorForSqaure(((row * rows) + col))); g2d.fillRect(col * cellSize, row * cellSize, cellSize, cellSize); g2d.setColor(borderColor); g2d.drawRect(col * cellSize, row * cellSize, cellSize, cellSize); } } g2d.dispose(); } } public class ColorBand { private float[] fractions; private Color[] colors; public ColorBand(float[] fractions, Color[] colors) { this.fractions = fractions; this.colors = colors; } public Color colorAt(float progress) { Color color = null; if (fractions != null) { if (colors != null) { if (fractions.length == colors.length) { int[] indicies = getFractionIndicies(progress); float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]}; Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]}; float max = range[1] - range[0]; float value = progress - range[0]; float weight = value / max; color = blend(colorRange[0], colorRange[1], 1f - weight); } else { throw new IllegalArgumentException("Fractions and colours must have equal number of elements"); } } else { throw new IllegalArgumentException("Colours can't be null"); } } else { throw new IllegalArgumentException("Fractions can't be null"); } return color; } protected int[] getFractionIndicies(float progress) { int[] range = new int[2]; int startPoint = 0; while (startPoint < fractions.length && fractions[startPoint] <= progress) { startPoint++; } if (startPoint >= fractions.length) { startPoint = fractions.length - 1; } range[0] = startPoint - 1; range[1] = startPoint; return range; } protected Color blend(Color color1, Color color2, double ratio) { float r = (float) ratio; float ir = (float) 1.0 - r; float rgb1[] = new float[3]; float rgb2[] = new float[3]; color1.getColorComponents(rgb1); color2.getColorComponents(rgb2); float red = rgb1[0] * r + rgb2[0] * ir; float green = rgb1[1] * r + rgb2[1] * ir; float blue = rgb1[2] * r + rgb2[2] * ir; if (red < 0) { red = 0; } else if (red > 255) { red = 255; } if (green < 0) { green = 0; } else if (green > 255) { green = 255; } if (blue < 0) { blue = 0; } else if (blue > 255) { blue = 255; } Color color = null; try { color = new Color(red, green, blue); } catch (IllegalArgumentException exp) { NumberFormat nf = NumberFormat.getNumberInstance(); System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue)); exp.printStackTrace(); } return color; } } } You could... Predefine the colors up-front import java.awt.Color; 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 class TestPane extends JPanel { private int cols = 5; private int rows = 5; private int cellSize = 50; private Color[] colors = new Color [] { new Color(64, 0, 0), new Color(79, 0, 0), new Color(94, 0, 0), new Color(109, 0, 0), new Color(124, 0, 0), new Color(139, 0, 0), new Color(154, 0, 0), new Color(169, 0, 0), new Color(184, 0, 0), new Color(199, 0, 0), new Color(214, 0, 0), new Color(229, 0, 0), new Color(244, 0, 0), new Color(0, 0, 64), new Color(0, 0, 80), new Color(0, 0, 96), new Color(0, 0, 112), new Color(0, 0, 128), new Color(0, 0, 144), new Color(0, 0, 160), new Color(0, 0, 176), new Color(0, 0, 192), new Color(0, 0, 208), new Color(0, 0, 224), new Color(0, 0, 240), }; public TestPane() { } #Override public Dimension getPreferredSize() { return new Dimension(cols * cellSize, rows * cellSize); } #Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Color borderColor = new Color(0, 0, 0, 64); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { g2d.setColor(colors[((row * rows) + col)]); g2d.fillRect(col * cellSize, row * cellSize, cellSize, cellSize); g2d.setColor(borderColor); g2d.drawRect(col * cellSize, row * cellSize, cellSize, cellSize); } } g2d.dispose(); } } }
Why won't gc.clearRect clear the canvas?
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()
Ball Falling follow each other
I am writing the implementation of Galton Board in Java by using Java awt, Swing and thread. My Program has three text field to choose number of slots, number of balls, and number of ball drops at the same time, two buttons one for display and one for start the program. I try to make it work like I can choose the amount of balls and click start and the balls auto falling down the chimney. My program currently can drop any balls, but they are falling at the same time, any ideas to make the ball falling follow each other?. Any suggestions or help are appreciated, Thank you. This is Main.Class import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.Random; import javax.swing.*; public class Main extends JFrame { private String num_slots; private String num_balls; private String ball_free; private JButton Display; private JButton Start; private JPanel textpanel; private JPanel mainpanel; private JPanel graphpanel; public Main() { textpanel = new JPanel(); textpanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20)); textpanel.add(new JLabel("Number of Slots")); final JTextField text1 = new JTextField(10); textpanel.add(text1); textpanel.add(new JLabel("Number of Balls")); final JTextField text2 = new JTextField(10); textpanel.add(text2); textpanel.add(new JLabel("How many balls can be freed")); final JTextField text3 = new JTextField(10); textpanel.add(text3); Display = new JButton("Display"); textpanel.add(Display); Start = new JButton("Start"); textpanel.add(Start); // Create panel p2 to hold a text field and p1 mainpanel = new JPanel(new BorderLayout()); mainpanel.add(textpanel, BorderLayout.NORTH); /* * graphpanel = new JPanel(); graphpanel.setLayout(new * BoxLayout(graphpanel, BoxLayout.Y_AXIS)); */ add(mainpanel, BorderLayout.CENTER); Display.addActionListener(new ActionListener() { #Override public void actionPerformed(ActionEvent e) { if (e.getSource() == Display) { num_slots = text1.getText(); int slots = Integer.parseInt(num_slots); num_balls = text2.getText(); int balls = Integer.parseInt(num_balls); MainPanel pa = new MainPanel(slots, balls); mainpanel.add(pa); mainpanel.revalidate(); } } }); Start.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (e.getSource() == Start) { num_slots = text1.getText(); int slots = Integer.parseInt(num_slots); num_balls = text2.getText(); int balls = Integer.parseInt(num_balls); MainPanel pa = new MainPanel(slots, balls); mainpanel.add(pa, BorderLayout.CENTER); pa.start(); mainpanel.revalidate(); mainpanel.repaint(); } } }); } public static void main(String[] args) { // TODO Auto-generated method stub Main frame = new Main(); frame.setTitle("The Galton board"); frame.setSize(1000, 800); frame.setLocationRelativeTo(null); // Center the frame frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.setAutoRequestFocus(true); } } main panel class contains the chimneys and balls import java.awt.Color; import java.awt.Graphics; import java.util.Random; import javax.swing.JPanel; class MainPanel extends JPanel implements Runnable { private int num; private int number_ball; public static int start_y = 100; private float ball_x = 385; private float ball_y = 50; private float radius = 15; private static int panel_x = 300; private static int panel_y = 100; private int diameter = 20; private int last_x = 0; private final static Random generator = new Random(); ArrayList<Balls> list_ball = new ArrayList<Balls>(); private int m_interval = 100; private Timer m_timer; public MainPanel() { } public MainPanel(int number) { num = number; } public MainPanel(int number, int ball) { num = number; number_ball = ball; for (int i = 1; i <= number_ball; i++) { list_ball.add(new Balls()); } m_timer = new Timer(m_interval, new TimerAction()); } public int getPanel_y() { return panel_y; } public void start() { m_timer.setInitialDelay(250); m_timer.start(); } #Override protected void paintComponent(Graphics g) { int start_y = 100; panel_x = 300; panel_y = 100; diameter = 20; last_x = 0; super.paintComponent(g); if (num % 2 == 0) { for (int i = 1; i <= num; i++) { if ((i % 2) != 0) { for (int k = 1; k <= num; k++) { g.setColor(Color.BLUE); g.fillOval(panel_x, panel_y, diameter, diameter); panel_x = panel_x + 40; } } else if ((i % 2) == 0) { for (int k = 1; k <= num + 1; k++) { g.setColor(Color.BLUE); g.fillOval(panel_x - 20, panel_y, diameter, diameter); panel_x = panel_x + 40; } } panel_y = panel_y + 40; panel_x = 300; } } else if (num % 2 != 0) { for (int i = 1; i <= num; i++) { if ((i % 2) != 0) { for (int k = 1; k <= num; k++) { g.setColor(Color.BLUE); g.fillOval(panel_x, panel_y, diameter, diameter); panel_x = panel_x + 40; } } else if ((i % 2) == 0) { for (int k = 1; k <= num + 1; k++) { g.setColor(Color.BLUE); g.fillOval(panel_x - 20, panel_y, diameter, diameter); panel_x = panel_x + 40; } } panel_y = panel_y + 40; panel_x = 300; } } for (int n = 40; n < panel_y - 40; n = n + 40) { if (num % 2 == 0) { g.drawLine(panel_x - 50 + n, panel_y - 10, panel_x - 50 + n, panel_y + 80); g.drawLine(panel_x, panel_y + 80, panel_x - 50 + n, panel_y + 80); last_x = panel_x - 50 + n; } else if (num % 2 != 0) { g.drawLine(panel_x - 30 + n, panel_y - 10, panel_x - 30 + n, panel_y + 80); g.drawLine(panel_x, panel_y + 80, panel_x - 30 + n, panel_y + 80); last_x = panel_x - 30 + n; } } for (int i = 0; i < list_ball.size(); i++) { list_ball.get(i).draw(g); } } class TimerAction implements ActionListener { public void actionPerformed(ActionEvent e) { for (int i = 0; i < list_ball.size(); i++) { list_ball.get(i).move(); //return; //m_timer.stop(); repaint(); } } Balls Class import java.awt.geom.Ellipse2D; import java.util.Random; import java.awt.*; public class Balls { private Ellipse2D.Double thisBall; private int Ball_x; private int Ball_y; public int radius; public int start_y; private final static Random generator = new Random(); Mainpanel pa = new Mainpanel(); public Balls() { start_y = 100; Ball_x = 385; Ball_y = 50; radius = 15; } public void draw(Graphics g) { g.setColor(Color.RED); g.fillOval(Ball_x, Ball_y, radius, radius); } public void move() { if (Ball_y < pa.getPanel_y() + 65) { int direction = generator.nextInt(2); Ball_y = Ball_y + 5; if (Ball_y == start_y - 10 && start_y < pa.getPanel_y()) { if (direction == 0) { Ball_x = Ball_x - 20; } else Ball_x = Ball_x + 20; start_y = start_y + 40; } System.out.println(Ball_y); System.out.println(pa.getPanel_y()); } // Ball_x = Ball_x + 5; } }
"My program currently can drop any balls, but they are falling at the same time, any ideas to make the ball falling follow each other?" One Option.. As seen in this answer, add a delayed state to each Ball. For example (from the same answer) class Shape { int randXLoc; int y = D_HEIGHT; int randomDelayedStart; boolean draw = false; boolean down = false; Color color; public Shape(int randXLoc, int randomDelayedStart, Color color) { this.randXLoc = randXLoc; this.randomDelayedStart = randomDelayedStart; this.color = color; } public void drawShape(Graphics g) { if (draw) { g.setColor(color); g.fillOval(randXLoc, y, 30, 30); } } public void decreaseDelay() { if (randomDelayedStart <= 0) { draw = true; } else { randomDelayedStart -= 1; } } } As you can see, the Shape is constructed with a randomDelayedStart. With every tick of the Timer, the randomDelayedStart is decreased until it reaches zero. In which case, the flag to draw is raised, allowing for the drawShape() to take effect. There is also a move() method (not shown for brevity) that uses the same flag, so the shape move() has no affect until the flag is raised
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); } }); } }
How do I draw rectangles in jpanel based on calculated averages
I have a gui where data is entered and the averages are calculated for 5 different sets of data. These are stored in an array with the five averages in the five positions. How do I make it draw rectangles in a jpanel to look like a graph of those 5 averages ?
..make it draw rectangles in a jpanel to look like a graph... Assuming, youre talking about bar graph, Have a look at this example : import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPanel; public class SimpleBarChart extends JPanel { private double[] value; private String[] languages; private String title; public SimpleBarChart(double[] val, String[] lang, String t) { languages = lang; value = val; title = t; } #Override public void paintComponent(Graphics graphics) { super.paintComponent(graphics); if (value == null || value.length == 0) { return; } double minValue = 0; double maxValue = 0; for (int i = 0; i < value.length; i++) { if (minValue > value[i]) { minValue = value[i]; } if (maxValue < value[i]) { maxValue = value[i]; } } Dimension dim = getSize(); int clientWidth = dim.width; int clientHeight = dim.height; int barWidth = clientWidth / value.length; Font titleFont = new Font("Book Antiqua", Font.BOLD, 15); FontMetrics titleFontMetrics = graphics.getFontMetrics(titleFont); Font labelFont = new Font("Book Antiqua", Font.PLAIN, 10); FontMetrics labelFontMetrics = graphics.getFontMetrics(labelFont); int titleWidth = titleFontMetrics.stringWidth(title); int q = titleFontMetrics.getAscent(); int p = (clientWidth - titleWidth) / 2; graphics.setFont(titleFont); graphics.drawString(title, p, q); int top = titleFontMetrics.getHeight(); int bottom = labelFontMetrics.getHeight(); if (maxValue == minValue) { return; } double scale = (clientHeight - top - bottom) / (maxValue - minValue); q = clientHeight - labelFontMetrics.getDescent(); graphics.setFont(labelFont); for (int j = 0; j < value.length; j++) { int valueP = j * barWidth + 1; int valueQ = top; int height = (int) (value[j] * scale); if (value[j] >= 0) { valueQ += (int) ((maxValue - value[j]) * scale); } else { valueQ += (int) (maxValue * scale); height = -height; } graphics.setColor(Color.blue); graphics.fillRect(valueP, valueQ, barWidth - 2, height); graphics.setColor(Color.black); graphics.drawRect(valueP, valueQ, barWidth - 2, height); int labelWidth = labelFontMetrics.stringWidth(languages[j]); p = j * barWidth + (barWidth - labelWidth) / 2; graphics.drawString(languages[j], p, q); } } public static void main(String[] args) { JFrame frame = new JFrame(); frame.setSize(350, 300); double[] value = new double[5]; String[] languages = new String[5]; value[0] = 1; languages[0] = "Visual Basic"; value[1] = 2; languages[1] = "PHP"; value[2] = 3; languages[2] = "C++"; value[3] = 4; languages[3] = "C"; value[4] = 5; languages[4] = "Java"; frame.getContentPane().add(new SimpleBarChart(value, languages, "Programming Languages")); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } Also see JFreeChart and if you dont mind using an external library. Example that you might need via #trashGod : example and its source code.