Java flood fill algorithm with different neighbourhood inside a grid - java

First of all, I wanted to say that I'm not very experienced Java programmer but was forced to learn things very quickly by school assignment. The assignment is to create a grid inside which we have a simple image. When a cell inside an image is clicked, then it's flood filled. The program needs to allow for different type of neighbourhood (4, 6 or 8). I managed to create a program that allows the user to paint the inside the image with different neighbourhoods, however now I'm trying to adjust the program so it would allow the flood fill. My question is - how can I set the boundaries for flood fill? I know that I can set the boundaries based on the color - that's why my image is painted in red, while I was planning to do the filling in black. However, I have no idea how can I put a condition using the color value. I checked different isssues on the net but couldn't quite apply anything to my program.
Here's the code I'm using (just the class for paining):
class MyCanvas extends JPanel implements MouseListener {
private int x,y;
ArrayList<Point> points = new ArrayList<Point>();
ArrayList<Point> points2 = new ArrayList<Point>();
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
int xSiatki = x/20;
int ySiatki = y/20; //gets the rectangle coordinate of grid
System.out.println("Siatka x: " + xSiatki + " " + "y: " + ySiatki );
if(clickEight){
points.add(new Point(xSiatki,ySiatki));
}
if(clickSix){
points2.add(new Point(xSiatki,ySiatki));
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Krata(g2d);
Rysunek(g2d);
if (clickStart){
Krata(g2d);
Rysunek (g2d);
repaint();
points.clear();
points2.clear();}
if (clickEight){
Krata(g2d);
Rysunek (g2d);
for(Point p: points) {
int x,y;
x = (int)p.getX();
y = (int)p.getY();
drawEightFlood(g2d, x, y);}
}
if (clickSix){
Krata(g2d);
Rysunek (g2d);
for(Point p: points2) {
int x,y;
x = (int)p.getX();
y = (int)p.getY();
drawSixFlood(g2d, x, y);}
}
}
private void drawEightFlood (Graphics2D g2d, int x, int y){
g2d.setColor(Color.BLACK);
g2d.fillRect (20*x, 20*y, 20, 20);
g2d.fillRect (20*x, 20*(y+1), 20, 20);
g2d.fillRect (20*(x+1), 20*y, 20, 20);
g2d.fillRect (20*(x-1), 20*y, 20, 20);
g2d.fillRect (20*x, 20*(y-1), 20, 20);
g2d.fillRect (20*(x-1), 20*(y+1), 20, 20);
g2d.fillRect (20*(x+1), 20*(y-1), 20, 20);
g2d.fillRect (20*(x-1), 20*(y-1), 20, 20);
g2d.fillRect (20*(x+1), 20*(y+1), 20, 20);
drawEightFlood (g2d, 20*x, 20*(y+1));
drawEightFlood (g2d, 20*(x+1), 20*y);
drawEightFlood (g2d, 20*(x+1), 20*(y+1));
drawEightFlood (g2d, 20*(x-1), 20*(y+1));
drawEightFlood (g2d, 20*x, 20*(y-1));
drawEightFlood (g2d, 20*(x-1), 20*(y-1));
drawEightFlood (g2d, 20*(x-1), 20*(y-1));
drawEightFlood (g2d, 20*(x-1), 20*y);
}
private void drawSixFlood (Graphics2D g2d, int x, int y){
g2d.setColor(Color.BLACK);
g2d.fillRect (20*x, 20*y, 20, 20);
g2d.fillRect (20*x, 20*(y-1), 20, 20);
g2d.fillRect(20*x, 20*(y+1), 20, 20);
g2d.fillRect(20*(x+1), 20*(y-1), 20, 20);
g2d.fillRect(20*(x+1), 20*y, 20, 20);
g2d.fillRect(20*(x-1), 20*y, 20, 20);
g2d.fillRect(20*(x-1), 20*(y+1), 20, 20);
drawSixFlood (g2d, 20*x, 20*(y+1));
drawSixFlood (g2d, 20*(x+1), 20*y);
drawSixFlood (g2d, 20*(x-1), 20*(y+1));
drawSixFlood (g2d, 20*x, 20*(y-1));
drawSixFlood (g2d, 20*(x-1), 20*(y-1));
drawSixFlood (g2d, 20*(x-1), 20*y);
}
public void Krata (Graphics2D g2d) { //code for grid
for(int i=0; i<54; i++) {
for(int j=0; j<34; j++) {
g2d.setColor(Color.BLACK);
g2d.drawRect (20*i, 20*j, 20, 20);
}
}
}
public void Rysunek (Graphics2D g2d){ //code for the image
for (int i=0; i<54;i++){
for (int j=0; j<34; j++){
if ((i == 0 || i == 53) && (j>12 && j<21 )){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if (((i>0 && i<11) || (i>42 && i<53)) &&(j == 13 || j == 20)){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if ((i > 16 && i < 37) && (j == 7 || j == 20)){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if ((i > 10 && i < 17) && (j == (23-i))){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if ((i > 36 && i < 43) && (j == (i-30))){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if (((i > 10 && i < 17) || (i>36 && i<43)) && (j==23 || j==18)){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
if ((i == 11 || i == 16 || i == 37 || i == 42) && (j>18 && j<23)){
g2d.setColor(Color.RED);
g2d.fillRect(20*i, 20*j, 20, 20);
}
}
}
}
}

The code you present is pretty incomprehensible (no comments, method-names in foreign language - i guess polish or sth like that, overall bad code style, etc.).I'd recommend painting to a BufferedImage instead of directly painting to the screen. This way you can easily check the color of single pixels or modify it or paint to the image and keep changes consistent:
int type = BufferedImage.TYPE_4BYTE_ABGR;
BufferedImage image = new BufferedImage(width , height , type);
Graphics g = image.getGraphics();
//draw stuff with g, just like in paintComponent(Graphics)
g.dispose();
//get color of pixel at (px , py)
Color c = new Color(image.getRGB(px , py));
//set color at pixel (px , py) to red
image.setRGB(px , py , Color.red.getRGB());

Related

Creating sliders with arrow buttons

How can I create a slider with two arrow buttons from the side? The arrows/triangle should turn white when clicked. And the slider should move each time the arrow button is clicked.
here's the link to what it should look like
and here's what I've done so far
int x=75;
void setup() {
size(600,400);
}
void draw() {
background(100);
fill (200);
rect (75, 25, 400, 50);
stroke(0);
if(mousePressed) {
if (mouseX >75 && mouseX <= 475)
{x=mouseX;}
}
fill(127,0,0);
rect (x, 20, 9, 60);
fill (255);
fill (200);
rect (10, 25, 50, 50);
{
if (mousePressed == true) {
fill(255);
} else {
fill(0);
}
triangle (50, 60, 50, 40, 15, 50);
}
fill (200);
rect (490, 25, 50, 50);
{
if (mousePressed == true) {
fill(255);
} else {
fill(0);
}
triangle (500, 60, 500, 40, 535, 50);
}
println(x);
}
When I click anywhere on the screen, my problem is that both arrows turn white. I need it to individually function. And the slider is not moving every time I click the arrow buttons
The following approach to this problem uses 4 different classes: ForwardArrow, BackArrow, Slider, and ValueField. Arrow fill color is controlled by the press() method of its respective class.
color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);
color GREEN = color(32, 175, 47);
ForwardArrow _fwdArrw;
BackArrow _backArrw;
ValueField _valueFld;
Slider _slider;
final int _sliderX = 90;
final int _sliderY = 40;
final int _sliderW = 200;
final int _sliderH = 30;
final int _txtSize = 22;
final int _initValue = 40;
final int _maxValue = 200;
final int _minValue = 0;
int value = _initValue;
class ValueField {
float x, y, w, h;
String title;
color fldColor;
color txtColor;
// Constructor
ValueField(int xpos, int ypos, float wt, float ht, String valueStr, color background, color foreground) {
x = xpos;
y = ypos;
w = wt;
h = ht;
title = valueStr;
fldColor = background;
txtColor = foreground;
}
void display(int val) {
// **** Value Field **** //
fill(fldColor); // erase old value
rect(x, y, w, h);
fill(txtColor); // text color
textSize(_txtSize);
textAlign(CENTER);
text(str(val), x, y, w, h);
// **** Slider bar **** //
fill(255);
rect(_sliderX, _sliderY, _sliderW*val/_maxValue, _sliderH);
}
}
class ForwardArrow {
float x, y, w, h;
color arrwColor;
// Constructor
ForwardArrow(int xpos, int ypos, float wt, float ht, color background) {
x = xpos;
y = ypos;
w = wt;
h = ht;
arrwColor = background;
}
void display() {
fill(arrwColor); // arrow color
noStroke();
triangle(x, y, x, y + h, x + w, y + h/2 );
}
void press() {
fill(255); // arrow color
noStroke();
triangle(x, y, x, y + h, x + w, y + h/2 );
}
}
class BackArrow {
float x, y, w, h;
color arrwColor;
// Constructor
BackArrow(int xpos, int ypos, float wt, float ht, color background) {
x = xpos;
y = ypos;
w = wt;
h = ht;
arrwColor = background;
}
void display() {
fill(arrwColor);
noStroke();
triangle(x, y + h/2, x + w, y, x + w, y + h );
}
void press() {
fill(255);
noStroke();
triangle(x, y + h/2, x + w, y, x + w, y + h );
}
}
class Slider {
float x, y, w, h;
color barColor;
color trimColor;
// Constructor
Slider(int xpos, int ypos, float wt, float ht, color background, color foreground) {
x = xpos;
y = ypos;
w = wt;
h = ht;
barColor = background;
trimColor = foreground;
}
void display() {
stroke(0);
strokeWeight(1);
noFill();
rect(x, y, w, h);
}
}
void setup() {
size(500, 250);
background(BLUE);
_slider = new Slider(_sliderX, _sliderY, _sliderW, _sliderH, WHITE, BLACK);
_backArrw = new BackArrow(50, 40, 30, 30, GREEN);
_fwdArrw = new ForwardArrow(300, 40, 30, 30, GREEN);
_valueFld = new ValueField(380, 40, 60, 30, str(_initValue), WHITE, BLACK);
}
void draw() {
background(BLUE);
_valueFld.display(value);
_fwdArrw.display();
_backArrw.display();
_slider.display();
// FwdArrw Long Press
if ((mouseX >= _fwdArrw.x) && (mouseX <= _fwdArrw.x + _fwdArrw.w) && (mouseY >= _fwdArrw.y) && (mouseY <= _fwdArrw.y + _fwdArrw.h)) {
if (mousePressed == true) {
_fwdArrw.press();
value++;
if (value > _maxValue) {
value = _maxValue;
}
_valueFld.display(value);
}
}
// BackArrw Long Press
if ((mouseX >= _backArrw.x) && (mouseX <= _backArrw.x + _backArrw.w) && (mouseY >= _backArrw.y) && (mouseY <= _backArrw.y + _backArrw.h)) {
if (mousePressed == true) {
_backArrw.press();
value--;
if (value < _minValue) {
value = _minValue;
}
_valueFld.display(value);
}
}
}
A revision of your code follows;
int x=75;
void setup() {
size(600, 400);
}
void draw() {
background(100);
fill (200);
rect (75, 25, 400, 50); // slider bar
stroke(0);
fill(127, 0, 0);
rect (x, 20, 9, 60); // slider thumb
fill (200);
rect (10, 25, 50, 50); // back arrow
fill(0);
triangle (50, 60, 50, 40, 15, 50);
if ((mouseX >= 10) && (mouseX <= 10 + 50) && (mouseY >= 25) && (mouseY <= 25 + 50) ) {
if (mousePressed == true) {
fill(255);
triangle (50, 60, 50, 40, 15, 50);
x--;
if (x<75) {
x = 75; // minValue
}
} else {
fill(0);
triangle (50, 60, 50, 40, 15, 50);
}
}
fill (200);
rect (490, 25, 50, 50); //forward arrow
fill(0);
triangle (500, 60, 500, 40, 535, 50);
if ((mouseX >= 490) && (mouseX <= 490 + 50) && (mouseY >= 25) && (mouseY <= 25 + 50) ) {
if (mousePressed == true) {
fill(255);
triangle (500, 60, 500, 40, 535, 50);
x++;
if (x>466) {
x = 466; // maxValue
}
} else {
fill(0);
triangle (500, 60, 500, 40, 535, 50);
}
}
}
You've got part of the logic right for the slider/trackbar so it changes x only within a range. This happens horizontally only at this stage, but you can use the same logic to check horizontal limits as well. Similarly, you can check if the cursor is within the bounds of any rectangle (be it the slider or either of the buttons):
int x=75;
void setup() {
size(600, 400);
}
void draw() {
background(100);
// slider
fill (200);
rect (75, 25, 400, 50);
stroke(0);
if (mousePressed) {
if (mouseX >75 && mouseX <= 475)
{
x=mouseX;
}
}
fill(127, 0, 0);
rect (x, 20, 9, 60);
fill (255);
// left arrow button
fill (200);
rect (10, 25, 50, 50);
fill(0);
if (mousePressed == true) {
if (mouseX > 10 && mouseX <= 10 + 50 && mouseY > 25 && mouseY <= 25 + 50){
fill(255);
}
}
triangle (50, 60, 50, 40, 15, 50);
// right arrow button
fill (200);
rect (490, 25, 50, 50);
fill(0);
if (mousePressed == true) {
if (mouseX > 490 && mouseX <= 490 + 50 && mouseY > 25 && mouseY <= 25 + 50){
fill(255);
}
}
triangle (500, 60, 500, 40, 535, 50);
println(x);
}
Wouldn't it be nice if you could take that logic and instead of copy/pasting the different x,y,width,height parameters for the same 4 statements you could group that functionality in a reusable block of code ?
That what functions are for. You're already using them already (defining setup()/draw(), calling background()/fill()/etc.
The Processing Button example already provides the boolean overRect(int x, int y, int width, int height) function which is perfect for you're trying to achieve: pass in the x,y,width,height or a button and get back boolean value.
Here's your code using the overRect():
int x=75;
void setup() {
size(600, 400);
}
void draw() {
background(100);
// slider
fill (200);
rect (75, 25, 400, 50);
stroke(0);
if (mousePressed) {
if (mouseX >75 && mouseX <= 475)
{
x=mouseX;
}
}
fill(127, 0, 0);
rect (x, 20, 9, 60);
fill (255);
// left arrow button
fill (200);
rect (10, 25, 50, 50);
fill(0);
if (mousePressed && overRect(10, 25, 50, 50)) {
fill(255);
x--;
}
triangle (50, 60, 50, 40, 15, 50);
// right arrow button
fill (200);
rect (490, 25, 50, 50);
fill(0);
if (mousePressed && overRect(490, 25, 50, 50)){
fill(255);
x++;
}
triangle (500, 60, 500, 40, 535, 50);
// ensure x remains within the slide limits
x = constrain(x, 75, 475);
println(x);
}
boolean overRect(int x, int y, int width, int height) {
if (mouseX >= x && mouseX <= x+width &&
mouseY >= y && mouseY <= y+height) {
return true;
} else {
return false;
}
}

counter updating/repainting graphics

I'm creating a Hangman game where a player enters a word and the other player tries to guess that word. There are 26 JButtons on the screen (with each letter of the alphabet).
Each time a correct letter is chosen a counter variable increments. The number of the counter variable dictates how much of the hangman is drawn (7 is when the hangman is fully drawn). I can get counter to increment when the correct letter is chosen but I cannot get parts of the hangman to be drawn when it does increment.
Here is my Hangman class that draws the Hangman and includes the incrementCounter method:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class HangMan extends JPanel implements ActionListener {
private int xS = 8;
private int yS = 30;
public int counter;
private Color hatColor = Color.BLACK;
private int dx = 0;
private int dy = 0;
public HangMan(int initalX, int initalY) {
// starting location
xS = initalX;
yS = initalY;
counter = 0;
Dimension dim = new Dimension(250, 475);
this.setPreferredSize(dim);
setFocusable(true);
requestFocusInWindow();
this.setVisible(true);
}
public void drawHangMan(Graphics g) {
g.setColor(Color.BLACK);
if (counter == 0) {
repaint();
}
if (counter == 1) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
repaint();
}
if (counter == 2) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
repaint();
}
if (counter == 3) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
drawBody(xS + 25, yS + 80, xS + 25, yS + 175, g); // body
repaint();
}
if (counter == 4) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
drawBody(xS + 25, yS + 80, xS + 25, yS + 175, g); // body
drawLeftLeg(xS - 20, yS + 225, xS + 25, yS + 175, g); //left leg
repaint();
}
if (counter == 5) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
drawBody(xS + 25, yS + 80, xS + 25, yS + 175, g); // body
drawLeftLeg(xS - 20, yS + 225, xS + 25, yS + 175, g); //left leg
drawRightLeg(xS + 25, yS + 175, xS + 65, yS + 225, g); //right leg
repaint();
}
if (counter == 6) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
drawBody(xS + 25, yS + 80, xS + 25, yS + 175, g); // body
drawLeftLeg(xS - 20, yS + 225, xS + 25, yS + 175, g); //left leg
drawRightLeg(xS + 25, yS + 175, xS + 65, yS + 225, g); //right leg
drawLeftArm(xS - 20, yS + 90, xS + 25, yS + 120, g); //left arm
repaint();
}
if (counter == 7) {
drawHat(xS + 15, yS - 1, 20, 25, g); // hat
drawBrim(xS + 10, yS + 25, 30, 6, g); // brim
drawHead(xS, yS + 30, 50, 50, g); // head
drawBody(xS + 25, yS + 80, xS + 25, yS + 175, g); // body
drawLeftLeg(xS - 20, yS + 225, xS + 25, yS + 175, g); //left leg
drawRightLeg(xS + 25, yS + 175, xS + 65, yS + 225, g); //right leg
drawLeftArm(xS - 20, yS + 90, xS + 25, yS + 120, g); //left arm
drawRightArm(xS + 25, yS + 120, xS + 70, yS + 90, g); //right arm
repaint();
}
}
public void drawLeftArm(int a, int b, int x, int y, Graphics g) {
g.drawLine(a, b, x, y); //left arm
repaint();
}
public void drawRightArm(int a, int b, int x, int y, Graphics g) {
g.drawLine(a, b, x, y); //left arm
repaint();
}
public void drawLeftLeg(int a, int b, int x, int y, Graphics g) {
g.drawLine(a, b, x, y); //left arm
repaint();
}
public void drawRightLeg(int a, int b, int x, int y, Graphics g) {
g.drawLine(a, b, x, y); //left arm
repaint();
}
public void drawBody(int a, int b, int x, int y, Graphics g) {
g.drawLine(a, b, x, y); //left arm
repaint();
}
public void drawHead(int a, int b, int x, int y, Graphics g) {
g.drawOval(a, b, x, y); //left arm
repaint();
}
public void drawHat(int a, int b, int x, int y, Graphics g) {
g.drawRect(a, b, x, y); //left arm
repaint();
}
public void drawBrim(int a, int b, int x, int y, Graphics g) {
g.drawRect(a, b, x, y); //left arm
repaint();
}
public void drawHanger(Graphics g) {
g.fillRect(xS - 125, yS + 300, 80, 20);
g.drawLine(xS - 85, yS + 300, xS - 85, yS + 80);
g.drawLine(xS - 85, yS + 80, xS + 22, yS + 80);
}
public void incrementCounter() {
counter++;
System.out.println("counter = " + counter);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawHangMan(g);
drawHanger(g);
repaint();
g.setFont(new Font("Sherif", Font.BOLD, 40));
}
public void actionPerformed(ActionEvent e) {
repaint();
}
}
Now here is my Button Class that draws the 26 JButtons and includes the ActionListener that will call the update method every time a button is clicked
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Button extends JPanel {
JButton[] grid = new JButton[26];
Dashes dash;
public Button(String str, Dashes dash) {
this.dash = dash;
final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Dimension dim = new Dimension(360, 360);
this.setPreferredSize(dim);
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
System.out.println(action);
dash.update(action);
dash.repaint();
/*
add(new JLabel(action + ""));
setVisible(true);
*/
}
};
for (int i = 0; i < grid.length; i++) {
grid[i] = (JButton) this.add(new JButton(alphabet.charAt(i) + ""));
grid[i].addActionListener(listener);
this.setVisible(true);
}
}
}
and here is my Dashes class that contains the update method
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Dashes extends JPanel {
JLabel label;
String word;
String guess = "";
HangMan hang;
public Dashes(String word) {
this.word = word;
hang = new HangMan(150, 150);
for (int i = 0; i < word.length(); i++) {
guess += " ";
}
word = word.toUpperCase();
Dimension dim = new Dimension(1500, 300);
this.setPreferredSize(dim);
this.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawDashes(g2d);
}
private void drawDashes(Graphics2D g2d) {
for (int i = 0; i < word.length() * 50; i += 50) {
g2d.draw(new Line2D.Double(100.0 + i, 200.0, 125.0 + i, 200.0));
for (int j = 0; j < guess.length(); j++) {
g2d.drawString(guess.charAt(j) + "", 108 + j * 50, 198);
}
// g2d.drawString("m", 108 + i, 198);
}
}
public void update(String str) {
for (int i = 0; i < word.length(); i++) {
if (str.equals(word.charAt(i) + "")) {
guess = guess.substring(0, i) + str + guess.substring(i + 1);
hang.incrementCounter();
hang.repaint();
}
}
}
}
I'm sorry for making such a small problem so long. I would like to mention that if I initially set counter to be 2, for example, it would correctly draw the hat, brim and head. Some background: I was assigned a Java graphics project without ever actually having been taught graphics!
1 - Remove repaint() from the paint logic (as said in comment)
2 - in Dashes.update() use String.equalsIgnoreCase() instead of String.equals() (probably you have lowercase word and are comparing with uppercase charactere from the Button class).
3 - in Dashes.update() increment counter and repaint HangMan only if you miss:
public void update(String str) {
boolean found = false;
for (int i = 0; i < word.length(); i++) {
if (str.equalsIgnoreCase(word.charAt(i) + "")) {
guess = guess.substring(0, i) + str + guess.substring(i + 1);
found = true;
}
}
if(!found) {
hang.incrementCounter();
hang.repaint();
}
}

Graphics keep resetting in JFrame

I recently started with Java and now I got stuck with a simple project. I want to draw a line and that works, but when i draw another line the first line disappears. I have no idea how to get it so I can keep drawing lines.
This is my code:
package com.example.paint;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ClickEvent extends MouseAdapter {
private Paint paint;
boolean click = false;
boolean clear = false;
int startX;
int startY;
int endX;
int endY;
int firstTime = 1;
public ClickEvent(Paint paint, Handler handler, Line line) {
this.paint = paint;
}
public void mousePressed(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
if (mouseOver(mx, my, 750, 560, 83, 40)) {
clear = true;
}
if (mouseOver(mx, my, 0, 0, 40, 40)) {
paint.color = "Black";
}
if (mouseOver(mx, my, 0, 40, 40, 40)) {
paint.color = "Blue";
}
if (mouseOver(mx, my, 0, 80, 40, 40)) {
paint.color = "Green";
}
if (mouseOver(mx, my, 0, 120, 40, 40)) {
paint.color = "Red";
}
if (!mouseOver(mx, my, 0, 0, 40, 160) && !mouseOver(mx, my, 750, 560, 83, 40)) {
clear = false;
startX = mx;
startY = my;
click = true;
}
}
public void mouseReleased(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
if (!mouseOver(mx, my, 0, 0, 40, 160) && !mouseOver(mx, my, 750, 560, 83, 40)) {
endX = mx;
endY = my;
click = false;
}
}
private boolean mouseOver(int mx, int my, int x, int y, int width, int height) {
if (mx > x && mx < x + width) {
if (my > y && my < y + height) {
return true;
} else
return false;
} else
return false;
}
public void tick() {
}
public void render(Graphics g) {
Font font = new Font("Arial", 1, 30);
Font font1 = new Font("Arial", 1, 13);
g.setColor(Color.black);
g.fillRect(0, 0, 40, 40);
g.setColor(Color.blue);
g.fillRect(0, 40, 40, 40);
g.setColor(Color.green);
g.fillRect(0, 80, 40, 40);
g.setColor(Color.red);
g.fillRect(0, 120, 40, 40);
g.setColor(Color.black);
g.drawRect(750, 560, 83, 40);
g.setFont(font);
g.drawString("Clear", 755, 590);
g.setFont(font1);
if (paint.color == "Red") {
g.setColor(Color.red);
g.drawString("Color: " + paint.color, 745, 15);
} else if (paint.color == "Blue") {
g.setColor(Color.blue);
g.drawString("Color: " + paint.color, 745, 15);
} else if (paint.color == "Green") {
g.setColor(Color.green);
g.drawString("Color: " + paint.color, 745, 15);
} else if (paint.color == "Black") {
g.setColor(Color.black);
g.drawString("Color: " + paint.color, 745, 15);
} else {
g.setColor(Color.black);
g.drawString("Color: ", 745, 15);
}
if (!clear) {
if ("Red".equals(paint.color) && !click) {
g.setColor(Color.red);
g.drawLine(startX, startY, endX, endY);
} else if ("Green".equals(paint.color) && !click) {
g.setColor(Color.green);
g.drawLine(startX, startY, endX, endY);
} else if ("Blue".equals(paint.color) && !click) {
g.setColor(Color.blue);
g.drawLine(startX, startY, endX, endY);
} else if ("Black".equals(paint.color) && !click) {
g.setColor(Color.black);
g.drawLine(startX, startY, endX, endY);
}
}
}
}
Some of the code is part of a basic tutorial, but the rest I tried to do myself. If anyone knows how I can get it to keep drawing lines or if anyone has any other improvements I would really appreciate it.
The problem is that you're only saving one line to draw later, in the form of startX, startY, endX, endY.
Rather you could, at the end of each click, save the line as a new line object. Something like this:
class MyLine {
private final int startX, startY;
private final int endX, endY;
private final Color color;
public MyLine(int startX, int startY, int endX, int endY, Color color) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.color = color;
}
public void draw(Graphics g) {
g.setColor(color);
g.drawLine(startX, startY, endX, endY);
}
}
Add a list as a field to your class:
List<MyLine> lineList = new ArrayList<>();
And then, in the mouseReleased method, add a new Line to the list:
if (!mouseOver(mx, my, 0, 0, 40, 160) && !mouseOver(mx, my, 750, 560, 83, 40)) {
endX = mx;
endY = my;
click = false;
lineList.add(new MyLine(startX, starY, endX, endY, paint.color));
}
Additionally, you would have to change Paint, so that it holds the color as a Color object:
class Paint {
public Color color;
...
}
~~~~
paint.color = Color.black;
Which is much easier than saving strings.
Finally, loop over all of your lines to draw them, within your render method:
for(MyLine l : lineList) {
l.draw(g);
}

How to make a loop or something that does a task every 5 seconds and then reset itself?

I need to have the for loop at the bottom do everything in the body every 5 seconds but it's not working for some reason! Sorry if this sounds very dumb, I am very new to java! If you could help, that'd be great! Thanks! :)
package rBP;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class Main extends Applet implements MouseListener {
public void init() {
super.init();
addMouseListener(this);
}
public long numClicks = 0; // 16385
public int autoFingerNum = 0;
public int faultyButtonNum = 0;
public int slickButtonNum = 0;
public int coolButtonNum = 0;
public int heatSinkNum = 0;
public int superButtonNum = 0;
public int aFCost = 30;
public int aFValue = 1;
public int fBCost = 75;
public int fBValue = 3;
public int slBCost = 300;
public int slBValue = 10;
public int cBCost = 1000;
public int cBValue = 25;
public int hSCost = 5000;
public int hSValue = 80;
public int suBCost = 10000;
public int suBValue = 200;
#Override
public void paint(Graphics g) {
this.setSize(1010, 360);
g.setColor(Color.cyan);
g.fillRect(0, 0, 1010, 360); // background
g.setColor(Color.black);
g.fillOval(47, 47, 205, 205); // button outline
g.setColor(Color.red);
g.fillOval(50, 50, 200, 200); // button
g.setColor(Color.yellow);
g.fillRect(2, 5, 290, 30); // yellow boxes
g.fillRect(300, 25, 100, 250);
g.fillRect(410, 25, 100, 250);
g.fillRect(520, 25, 100, 250);
g.fillRect(630, 25, 100, 250);
g.fillRect(740, 25, 100, 250);
g.fillRect(850, 25, 100, 250);
g.setColor(Color.black);
g.drawLine(300, 100, 400, 100); // lines on yellow boxes
g.drawLine(410, 100, 510, 100);
g.drawLine(520, 100, 620, 100);
g.drawLine(630, 100, 730, 100);
g.drawLine(740, 100, 840, 100);
g.drawLine(850, 100, 950, 100);
g.drawLine(300, 190, 400, 190);
g.drawLine(410, 190, 510, 190);
g.drawLine(520, 190, 620, 190);
g.drawLine(630, 190, 730, 190);
g.drawLine(740, 190, 840, 190);
g.drawLine(850, 190, 950, 190);
g.fillRect(307, 197, 86, 71); // boxes around "buy" buttons
g.fillRect(417, 197, 86, 71);
g.fillRect(527, 197, 86, 71);
g.fillRect(637, 197, 86, 71);
g.fillRect(747, 197, 86, 71);
g.fillRect(857, 197, 86, 71);
g.setColor(Color.red);
g.fillRect(310, 200, 80, 65); // red "buy" buttons
g.fillRect(420, 200, 80, 65);
g.fillRect(530, 200, 80, 65);
g.fillRect(640, 200, 80, 65);
g.fillRect(750, 200, 80, 65);
g.fillRect(860, 200, 80, 65);
g.setColor(Color.black);
g.setFont(new Font("default", Font.BOLD, 12));
g.drawString("Number of Points: " + numClicks, 5, 25); // num of points
g.setFont(new Font("default", Font.BOLD, 20));
g.drawString("DO", 135, 120);
g.drawString("NOT", 127, 150);
g.drawString("PRESS", 115, 180);
g.setFont(new Font("default", Font.BOLD, 16));
g.drawString("AutoFinger", 310, 50);
g.drawString("FaultyButton", 411, 50);
g.drawString("SlickButton", 524, 50);
g.drawString("CoolButton", 635, 50);
g.drawString("HeatSink", 754, 50);
g.drawString("SuperButton", 851, 50);
g.drawString("+1p/5s", 310, 75);
g.drawString("+3p/5s", 434, 75);
g.drawString("+10p/5s", 540, 75);
g.drawString("+40p/5s", 648, 75);
g.drawString("+100p/5s", 756, 75);
g.drawString("+500p/5s", 866, 75);
g.drawString("Buy: 30P", 315, 240);
g.drawString("Buy: 75P", 425, 240);
g.drawString("Buy: 300P", 530, 240);
g.setFont(new Font("default", Font.BOLD, 15));
g.drawString("Buy: 1000P", 642, 240);
g.drawString("Buy: 5000P", 752, 240);
g.setFont(new Font("default", Font.BOLD, 13));
g.drawString("Buy: 10000P", 862, 240);
g.setFont(new Font("default", Font.BOLD, 12));
g.drawString("aFNumber: " + autoFingerNum, 305, 150);
g.drawString("fBNumber: " + faultyButtonNum, 415, 150);
g.drawString("sBNumber: " + slickButtonNum, 525, 150);
g.drawString("cBNumber: " + coolButtonNum, 635, 150);
g.drawString("hSNumber: " + heatSinkNum, 745, 150);
g.drawString("sBNumber: " + superButtonNum, 855, 150);
}
#Override
public void mouseClicked(MouseEvent e) {
if ((e.getX() > 50 && e.getX() < 250)
&& (e.getY() > 50 && e.getY() < 250)) {
numClicks++;
repaint();
}
if ((e.getX() > 310 && e.getX() < 390)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (aFCost - 1)) {
autoFingerNum++;
numClicks -= aFCost;
repaint();
}
if ((e.getX() > 420 && e.getX() < 500)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (fBCost - 1)) {
faultyButtonNum++;
numClicks -= fBCost;
repaint();
}
if ((e.getX() > 530 && e.getX() < 610)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (slBCost - 1)) {
slickButtonNum++;
numClicks -= slBCost;
repaint();
}
if ((e.getX() > 640 && e.getX() < 720)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (cBCost - 1)) {
coolButtonNum++;
numClicks -= cBCost;
repaint();
}
if ((e.getX() > 750 && e.getX() < 830)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (hSCost - 1)) {
heatSinkNum++;
numClicks -= hSCost;
repaint();
}
if ((e.getX() > 860 && e.getX() < 940)
&& (e.getY() > 200 && e.getY() < 265)
&& numClicks > (suBCost - 1)) {
superButtonNum++;
numClicks -= suBCost;
repaint();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
public void output() {
for (int i = 0; i >= 50; i++) { //<- I just set it at 50 for testing purposes
i = 0;
numClicks += autoFingerNum * aFValue;
numClicks += faultyButtonNum * fBValue;
numClicks += slickButtonNum * slBValue;
numClicks += coolButtonNum * cBValue;
numClicks += heatSinkNum * hSValue;
numClicks += superButtonNum * suBValue;
}
}
}
Timer + TimerTask might suit your needs. Here is a code sample:
TimerTask task = new MyTask();
Timer timer = new Timer();
timer.scheduleAtFixedRate(task, startTime, interval);
Where MyTask is:
public class MyTask extends TimerTask {
#Override
public void run() {
// do work here
}
}
Thread.sleep causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system. The sleep method can also be used for pacing, as shown below
boolean continueExec = true; //you can use this to exit the loop
public void output() {
while(this.continueExec ){
Thread.sleep(5000); //wait 5 seconds
numClicks += autoFingerNum * aFValue;
numClicks += faultyButtonNum * fBValue;
numClicks += slickButtonNum * slBValue;
numClicks += coolButtonNum * cBValue;
numClicks += heatSinkNum * hSValue;
numClicks += superButtonNum * suBValue;
}
}
Use javax.swing.Timer. You can schedule it to run your event handling code at any given time interval, or after any scheduled time, and this code will run in a Swing thread from where you can safely manipulate buttons, labels, etc.
If you just want drawing to change periodically, the timer could set some variable that have effect on your painting and then call repaint().
It is more complex to do with your own separate thread as it cannot touch any GUI components, unless SwingUtils.invokeLater or something similar is used.
Use a Thread to execute the statements of output()
Thread timer = new Thread(){
public void run(){
try{
while(true ){
numClicks += autoFingerNum * aFValue;
numClicks += faultyButtonNum * fBValue;
numClicks += slickButtonNum * slBValue;
numClicks += coolButtonNum * cBValue;
numClicks += heatSinkNum * hSValue;
numClicks += superButtonNum * suBValue;
repaint();
sleep(5000);
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
}
}
};
timer.start();

How do I stop my paint method form repeating twice?

Here is the code for a dice game that I am working on that outputs the results to a window. The paint method repeats twice, which is not good for me because I want the dice to roll once and then move on to the next frame. Please someone help me with this problem. Thank you in advance.
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class Dice extends JApplet {
public static int pause(int n)
{
try {
Thread.sleep(n);
} catch(InterruptedException e) {
}
return n;
}
public void Dice() {
JApplet app = new Dice();
JFrame frame = new JFrame("Dice Game");
frame.setBounds(30, 50, 1300, 650);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(app);
}
public void paint(Graphics g) {
int width = getWidth();
int height = getHeight();
int num = 0;
for (int i = 0; i < 7; i++) {
Random generator= new Random();
int number = generator.nextInt(6)+1;
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLACK);
g.drawRoundRect(550, 150, 200, 200, 50, 50);
System.out.println("Test");
if (number == 1) { //Roll one
num = 1;
g.setColor(new Color (0, 0, 0));
g.fillOval(640, 240, 20, 20);
pause(100);
} if (number == 2) { //Roll two
num = 2;
g.setColor(new Color (0, 0, 0));
g.fillOval(590, 290, 20, 20);
g.fillOval(690, 190, 20, 20);
pause(100);
} if (number == 3) { //Roll three
num = 3;
g.setColor(new Color (0, 0, 0));
g.fillOval(590, 290, 20, 20);
g.fillOval(640, 240, 20, 20);
g.fillOval(690, 190, 20, 20);
pause(100);
} if (number == 4) { //Roll four
num = 4;
g.setColor(new Color (0, 0, 0));
g.fillOval(590, 290, 20, 20);
g.fillOval(590, 190, 20, 20);
g.fillOval(690, 290, 20, 20);
g.fillOval(690, 190, 20, 20);
pause(100);
} if (number == 5) { //Roll five
num = 5;
g.setColor(new Color (0, 0, 0));
g.fillOval(590, 290, 20, 20);
g.fillOval(590, 190, 20, 20);
g.fillOval(640, 240, 20, 20);
g.fillOval(690, 290, 20, 20);
g.fillOval(690, 190, 20, 20);
pause(100);
} if (number == 6) { //Roll six
num = 6;
g.setColor(new Color (0, 0, 0));
g.fillOval(590, 190, 20, 20);
g.fillOval(590, 240, 20, 20);
g.fillOval(590, 290, 20, 20);
g.fillOval(690, 190, 20, 20);
g.fillOval(690, 240, 20, 20);
g.fillOval(690, 290, 20, 20);
pause(100);
}
}
g.setFont(new Font("TimesRoman", Font.PLAIN, 20));
g.drawString("You rolled a " + num, 590, 100);
pause(1000);
}
}
The short answer is - you can't. You don't control when painting occurs that is the domain of the RepaintManager.
You should also NEVER call Thread.sleep within the context of the Event Dispatching Thread and especially not within any paint method
You should avoid overriding paint and instead use paintComponent
You should avoid extending from JFrame and instead use something like JPanel, which actually has a paintComponent method.
Animation of this nature is best achieved by using a Swing Timer, which will allow to employee a pause which is maintained outside of the EDT, but is triggered again within in the EDT making it safer to perform painting and updates
Take a look at
Concurrency in Swing
How to Use Swing Timers
Performing Custom Painting
Painting in AWT and Swing
For more details about how painting works in Swing and how to achieve what you are trying to do
Updated with working example
Cause I'm lazy, I've utilised the Graphics 2D API to draw the dots. I did this because many of the dots appear in the same locations for many of the numbers...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DiceRoller {
public static void main(String[] args) {
new DiceRoller();
}
public DiceRoller() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Die());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Die extends JPanel {
private int number = 1;
public Die() {
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
number = (int) (Math.round((Math.random() * 5) + 1));
repaint();
}
});
timer.setRepeats(true);
timer.setInitialDelay(0);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(220, 220);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.BLACK);
g2d.drawRoundRect(10, 10, width - 20, height - 20, 50, 50);
List<Shape> dots = new ArrayList<>(6);
if (number == 1 || number == 3 || number == 5) {
int x = (width - 20) / 2;
int y = (height - 20) / 2;
dots.add(new Ellipse2D.Float(x, y, 20, 20));
}
if (number == 2 || number == 3 || number == 4 || number == 5 || number == 6) {
int x = ((width / 2) - 20) / 2;
int y = ((height / 2) - 20) / 2;
dots.add(new Ellipse2D.Float(x, y, 20, 20));
dots.add(new Ellipse2D.Float(x + (width / 2), y + (height / 2), 20, 20));
}
if (number == 4 || number == 5 || number == 6) {
int x = (width / 2) + (((width / 2) - 20) / 2);
int y = ((height / 2) - 20) / 2;
dots.add(new Ellipse2D.Float(x, y, 20, 20));
dots.add(new Ellipse2D.Float(x - (width / 2), y + (height / 2), 20, 20));
}
if (number == 6) {
int x = (((width / 2) - 20) / 2);
int y = (height - 20) / 2;
dots.add(new Ellipse2D.Float(x, y, 20, 20));
dots.add(new Ellipse2D.Float(x + (width / 2), y, 20, 20));
}
for (Shape dot : dots) {
g2d.fill(dot);
}
g2d.dispose();
}
}
}

Categories