Printing Java shapes with a delay - java

I am trying to create a program that solves the popular Towers of Hanoi game. I have succeeded in printing the disks and pegs, but I want the disks to print with a delay. For example, I want disk 7 to print, then disk 6 to print 1 second later. I tried this by putting it to sleep, but all it does is delay the whole frame from displaying, how do I make it display the shape with a delay. I have attached my code, thanks for any help!
package towersofhanoi;
import javax.swing.*;
import java.awt.*;
/*g.fillOval(60 = horizontal distance , 540= vertical distance, 400 = width, 60 = height) */
public class TowersOfHanoi extends JPanel {
public static void main(String[]args){
//Print the shapes and frame
TowersOfHanoi drawRectangle = new TowersOfHanoi();
JFrame frame = new JFrame("Towers of Hanoi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawRectangle);
frame.setSize(1250, 800);
frame.setVisible(true);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Color pegs = new Color (251, 129, 56);
g.setColor(pegs);
//peg 1
g.fillRect(250, 300, 25, 450);
//peg 2
g.fillRect(600, 300, 25, 450);
//peg 3
g.fillRect(950, 300, 25, 450);
//bottom
g.fillRect(200, 700, 825, 50);
//create a color for circles
Color circles = new Color (176,56, 251);
//cirle 7 (Labeled from bottom to top)
g.setColor(circles);
g.fillOval(60, 640, 400, 60);
g.setColor(Color.BLACK);
g.drawOval(60, 640, 400, 60);
try {
Thread.sleep(1000);
}
catch (InterruptedException ie) {
}
//circle 6
g.setColor(circles);
g.fillOval(85, 580, 350, 60);
g.setColor(Color.BLACK);
g.drawOval(85, 580, 350, 60);
try {
Thread.sleep(1000);
}
catch (InterruptedException ie) {
}
//circle 5
g.setColor(circles);
g.fillOval(110, 520, 300, 60);
g.setColor(Color.BLACK);
g.drawOval(110, 520, 300, 60);
//circle 4
g.setColor(circles);
g.fillOval(135, 465, 250, 55);
g.setColor(Color.BLACK);
g.drawOval(135, 465, 250, 55);
//circle 3
g.setColor(circles);
g.fillOval(160, 420, 200, 45);
g.setColor(Color.BLACK);
g.drawOval(160, 420, 200, 45);
//circle 2
g.setColor(circles);
g.fillOval(185, 380, 150, 40);
g.setColor(Color.BLACK);
g.drawOval(185, 380, 150, 40);
//circle 1
g.setColor(circles);
g.fillOval(210, 345, 100, 35);
g.setColor(Color.BLACK);
g.drawOval(210, 345, 100, 35);
}
}

My recommendation
separate out drawing in paintComponent() into the 3 constitute parts, these were previously separated by sleep statements
Use state inside the TowersOfHanoi object to control what should be drawn, I've used a simple counter
Use javax.swing.Timer to update the counter and request a repaint.
Notes
You cannot sleep on the UI thread. Swing is single threaded and this would stop events being processed.
javax.swing.Timer automatically fires the callback you give it on the UI thread.
paintComponent() can be called multiple times if windows are resized etc, therefore it is important to make it independent, hence my use of a counter.
Working example
public class TowersOfHanoi extends JPanel {
private int clock = 0;
private Color circles = new Color(176, 56, 251);
public static void main(String[] args) {
// Print the shapes and frame
TowersOfHanoi drawRectangle = new TowersOfHanoi();
JFrame frame = new JFrame("Towers of Hanoi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(drawRectangle);
frame.setSize(1250, 800);
frame.setVisible(true);
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
drawRectangle.nextFrame();
drawRectangle.repaint();
}
});
timer.setRepeats(true);
timer.start();
}
public void nextFrame() {
clock++;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
frame1(g);
if (clock >= 1) {
frame2(g);
}
if (clock >= 2) {
frame3(g);
}
}
private Color frame1(Graphics g) {
Color pegs = new Color(251, 129, 56);
g.setColor(pegs);
// peg 1
g.fillRect(250, 300, 25, 450);
// peg 2
g.fillRect(600, 300, 25, 450);
// peg 3
g.fillRect(950, 300, 25, 450);
// bottom
g.fillRect(200, 700, 825, 50);
// create a color for circles
// cirle 7 (Labeled from bottom to top)
g.setColor(circles);
g.fillOval(60, 640, 400, 60);
g.setColor(Color.BLACK);
g.drawOval(60, 640, 400, 60);
return circles;
}
private void frame2(Graphics g) {
// circle 6
g.setColor(circles);
g.fillOval(85, 580, 350, 60);
g.setColor(Color.BLACK);
g.drawOval(85, 580, 350, 60);
}
private void frame3(Graphics g) {
// circle 5
g.setColor(circles);
g.fillOval(110, 520, 300, 60);
g.setColor(Color.BLACK);
g.drawOval(110, 520, 300, 60);
// circle 4
g.setColor(circles);
g.fillOval(135, 465, 250, 55);
g.setColor(Color.BLACK);
g.drawOval(135, 465, 250, 55);
// circle 3
g.setColor(circles);
g.fillOval(160, 420, 200, 45);
g.setColor(Color.BLACK);
g.drawOval(160, 420, 200, 45);
// circle 2
g.setColor(circles);
g.fillOval(185, 380, 150, 40);
g.setColor(Color.BLACK);
g.drawOval(185, 380, 150, 40);
// circle 1
g.setColor(circles);
g.fillOval(210, 345, 100, 35);
g.setColor(Color.BLACK);
g.drawOval(210, 345, 100, 35);
}
}

Have you tried using Caldender() or System.currentTimeMillis()? If you do, you can get the current time. After you have gotten the time, do a while loop to check what the time is now. When you do LastTime - Now, to check how much time has passed.
This code is not tested, (But it should work).
long lastTime = System.currentTimeMillis();
while(true){
long now = System.currentTimeMillis();
if(lastTime - now == [YOUR PREFFERD WAITING TIME IN MS]){
break;
}
}
And now draw your graphics.

You should probably restructure you code so that paint component draws the current state of the system of pegs and rings. Then use a Swing timer to call a method that moves the state of the system then calls repaint().

Related

paintComponent is stressing me out; Hangman programming project

Ok, so I have a programming project due in a few hours and I am close to finished. I can only paint certain parts of the hangman at a time, which is dependent on the amount of incorrect tries by the user. The teacher of my programming class requires the creation of the hangman drawing to be in a different class. The problem I'm having is sending over the number of incorrect tries to a class with the paintComponent.
if(updatedChallenge == challenge)
{
incorrectTries += 1;
}
challenge = updatedChallenge;
The challenge == updated challenge refers to the hidden word before the user's guess and the hidden word after the user's guess. If they are still equal that means the user made an incorrect choice. 1 gets added to the total number of incorrect tries.
Here is my other class:
class HangmanPicture extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawLine(250, 300, 300, 300); //Platform
g.drawLine(275, 300, 275, 200); //Pole
g.setColor(Color.YELLOW);
g.drawLine(275, 200, 350, 200); //Rope
g.drawLine(350, 200, 350, 225); //Noose
g.setColor(Color.CYAN);
g.drawOval(350, 225, 15, 15); //Head
g.drawLine(350, 230, 350, 260); //Torso
g.drawLine(350, 240, 340, 230); //Left Arm
g.drawLine(350, 240, 360, 230); // Right Arm
g.drawLine(350, 260, 330, 280); // Left Leg
g.drawLine(350, 260, 390, 280); // Right Leg
}
}
I want to put an if statement where each body part gets added after each incorrect try, which requires me to send the number of incorrect tries to the class. Whenever I try to send the number, it always somehow interferes with paintComponent
Any help would be greatly appreciated, I'm desperate. Thanks in advanced!
Since you are extending the JPanel class. We can add extra methods and fields to the class and use them where HangmanPicture is being used.
HangmanPicture panel = new HangmanPicture();
...
if(updatedChallenge == challenge)
{
panel.addIncorrectAttempt();
}
challenge = updatedChallenge;
class HangmanPicture extends JPanel
{
private int incorrectAttempts = 0;
// Add one to counter
public void addIncorrectAttempt(){
incorrectAttempte++;
}
// Get how many times the player entered an incorrect number
public int getIncorrectAttempts(){
return incorrectAttempts;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLACK);
if( incorrectAttempts >= 1 ){
g.drawLine(250, 300, 300, 300); //Platform
}
if( incorrectAttempts >= 2 ){
g.drawLine(275, 300, 275, 200); //Pole
}
}
}

Unwanted Line Drawn by Java QuadCurve.2D

"I am trying to draw a QuadCurve line in Java. I am able to do this when I hard code the x and y values in each line, but when I try to draw the lines from a loop I get an unwanted line on the top. I want to have it in a loop so that I can create the values in another location and feed the values to my Drawing class. I think it may be a looping issue. I "stepped into" the code and the values in the array are all correct. I am in college so any help is appreciated. Thank you!
This code works:"
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(Color.BLUE);
Shape drawLine1A = new QuadCurve2D.Float(40, 450, 100, 300, 210, 180);
Shape drawLine2A = new QuadCurve2D.Float(210, 180, 315, 150, 390, 240);
Shape drawLine3A = new QuadCurve2D.Float(390, 240, 430, 242, 480, 245);
g2.draw(drawLine1A);
g2.draw(drawLine2A);
g2.draw(drawLine3A);
"This code does not work correctly:"
Graphics2D g2 = (Graphics2D) g.create();
g2.setPaint(Color.BLUE);
Shape line;
int[] x = {40, 100, 210, 210, 315, 390, 390, 430, 480};
int[] y = {450, 300, 180, 180, 150, 240, 240, 242, 245};
int k;
int h;
for(int i = 0; i < 7; i++)
{
k = i + 1;
h = k + 1;
line = new QuadCurve2D.Float(x[i], y[i], x[k], y[k], x[h], y[h]);
g2.draw(line);
}
"I figured this out after. i had to increment i by 3 in order to have the coordinates in the right spots. Simple fix. I was looking at it for too long!"

How to get a graphics-method, such as paint, to activate on a button-click

For a school-project, we've recieved a set amount of figures we're supposed to paint on a canvas with the normal Java-graphics method .paint(). This is supposed to be controlled with the help of a few buttons, each painting a different mix of colors. The paint-method is quite easy and works but when we try to connect the buttons, nothing happens but the buttons appearing on the screen. The code reads as following:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class MarcusErikaGrf2 extends Applet implements ActionListener {
Button knapp, knapp2, knapp3, knapp4, knapp5;
boolean svart=false, rod=false, gul=false, gron=false, rensa=false;
int tx[],ty[],pox[],poy[],pgx[],pgy[],pgxf[],pgyf[],bx[],by[],bxf[],byf[],hf[],hy[];
Polygon txy, po, pg, pgf, b, bf, hxy;
public void init (){
this.setSize(800,900);
this.setBackground(Color.white);
this.setLocation(200,1);
knapp= new Button ("Svart");
knapp2= new Button ("Röd & Rosa");
knapp3= new Button ("Gul & Orange");
knapp4 = new Button ("Grön & Blå");
knapp5 = new Button ("Rensa fönstret");
knapp.addActionListener(this);
knapp2.addActionListener(this);
knapp3.addActionListener(this);
knapp4.addActionListener(this);
knapp5.addActionListener(this);
add(knapp);
add(knapp2);
add(knapp3);
add(knapp4);
add(knapp5);
int tx[] = {375,475,425};
int ty[] = {110,110,250};
int pox[] = {65,120,120,65,50};
int poy[] = {350,350,450,450,400};
int pgx[] = {35,88,98,88,35,25};
int pgy[] = {210,210,270,330,330,270};
int pgxf[] = {36,87,97,87,36,26};
int pgyf[] = {211,211,270,329,329,270};
int bx[] = {372, 400, 395, 420, 415, 440/*TP*/, 415, 400, 405, 382, 387 };
int by[] = {60 , 67 , 70 , 77 , 80 , 87 /*TP*/, 95, 88 , 85 , 75 , 70};
int bxf[] = {373,399,394,419,414,439,416,401,406,383,388};
int byf[] = {61,67,70,77,80,86,94,88,85,75,70};
int hx[] = {150,185,225};
int hy[] = {176,120,176};
Polygon txy = new Polygon(tx,ty,tx.length);
Polygon po = new Polygon(pox,poy,pox.length);
Polygon pg = new Polygon(pgx,pgy,pgx.length);
Polygon pgf = new Polygon(pgxf,pgyf,pgxf.length);
Polygon b = new Polygon(bx,by,bx.length);
Polygon bf = new Polygon(bxf,byf,bxf.length);
Polygon hxy = new Polygon(hx,hy,hx.length);
}
#Override
public void paint(Graphics g){
if(svart == true){
g.setColor(Color.black);
g.drawRect(50, 50, 30, 150); //Rektangel 1
g.drawRect(90,50,30,150); //Rektangel 2
g.drawOval(140, 60, 40,30); //Öga 1
g.drawOval(200, 62, 40, 30); //Öga 2
g.fillOval(147,67,15,15); //Pupill 1
g.fillOval(218,69,15,15); //Pupill 2
g.fillOval(310,100,50,120); //Svart oval, Stor
g.fillOval(310, 50, 22, 30); //Svart oval, Medium
g.fillOval(270, 220, 20, 28); //Svart oval, Liten
g.drawOval(100,230,140,40); //Rosa oval, outline
g.fillOval(370,250,100,50); //Svart oval, horisontell
g.drawRect(200,300,180,150); //Grön rektangel, outline
g.drawRect(170,369,10,130);
g.drawRect(140,369,10,130);
g.fillOval(250,480,28,40);
g.fillOval(400,480,14,20);
g.drawOval(280,520,122,200);
g.drawOval(160, 570, 80, 100);
g.drawOval(50,680,140,40);
g.drawRect(65,500,65,150);
g.drawPolygon(pg);
g.drawPolygon(b);
g.setColor(Color.white);
g.fillOval(317, 65, 8, 8); //Vit prick i svart oval, Medium
g.fillOval(277, 235, 6, 6); //Vit prick i svart oval, Liten
}
else if(rod == true){
g.setColor(Color.red);
g.fillOval(161,571,79,99);
g.fillOval(255, 150, 50, 70);
g.setColor(Color.pink);
g.fillOval(101, 231, 138, 38); //Rosa oval
g.fillPolygon(bf);
g.setColor(Color.white);
g.fillOval(255, 170, 50, 50);
}
else if(gron == true){
g.setColor(Color.blue);
g.fillRect(51, 51, 29, 149); //Rektangel 1
g.fillRect(91, 51, 29, 149); //Rektangel 2
g.fillRect(66,501,64,149);
g.fillPolygon(txy);
g.setColor(Color.green);
g.fillRect(201, 301, 179, 149); //Grön rektangel
g.fillOval(51,681,139,38);
g.fillPolygon(pgf);
}
else if(gul == true){
g.setColor(Color.yellow);
g.fillRect(171,370,9,129);
g.fillRect(141,370,9,129);
g.fillOval(281,521,120,198);
g.setColor(Color.orange);
g.fillPolygon(po);
g.fillPolygon(hxy);
g.fillOval(150, 160, 45, 45);
g.fillOval(180, 160, 45, 45);
}
else if(rensa == true){
repaint();
}
}
public void actionPerformed (ActionEvent e){
if(e.getSource() == knapp){
svart = true;
}
else if(e.getSource() == knapp2){
rod = true;
}
else if(e.getSource() == knapp3){
gul = true;
}
else if(e.getSource() == knapp4){
gron = true;
}
else if(e.getSource() == knapp5){
rensa = true;
}
}
}
What are we missing?
In your actionPerformed(...) method you need to invoke:
repaint();
This tells the component to repaint itself.
else if(rensa == true){
repaint();
}
Never invoke repaint() from within a painting method. A painting method is for doing the painting, not scheduling the painting.

Bouncing multiple lines with fixed coordinates off walls in java graphics [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I want to store the fixed coordinates and then increment the coordinates until they reache the edge of the screen.
Here's my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Name extends JPanel
{
int x, y, w, h, xdir, ydir;
public Name ()
{
}
public void paintComponent (Graphics g)
{
super.paintComponent (g);
g.drawLine(110+x, 300+y, 95+x, 400+y);
g.drawLine(110, 300, 123, 350);
g.drawLine(135, 300, 123, 350); //M
g.drawLine(135, 300, 150, 400);
g.drawOval (150, 300, 15, 15); // i
g.fillOval (150, 300, 15, 15);
g.drawLine (155, 320, 155, 400);
g.drawLine (172, 300, 172, 400); // k
g.drawLine (172, 350, 185, 300);
g.drawLine (172, 350, 185, 400);
g.drawLine (190, 360, 265, 360); // e
g.drawArc (190, 325, 75, 75, 360, 180);
g.drawArc (190, 330, 75, 75, 168, 180);
w = getSize ().width;
h = getSize ().height;
xdir = 1;
ydir = 1;
x = x + xdir;
y = y+ ydir;
if (x > w || x < 0)
{
xdir = -1 * xdir;
}
if (y > h || y < 0)
{
ydir = -1 * ydir;
}
repaint ();
MyLib.delay (25);
} // paint method
public static void main (String[] args)
{
JFrame frame = new JFrame ("NameBounce");
frame.getContentPane ().add (new Name ());
frame.setSize (500, 500);
frame.setVisible (true);
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
} // main method
} // Name class
I've tried storing the coordinates into array lists but had no luck.
I've been trying to avoid hard coding the entire program.
Use something like Path2D to define the shapes you want to draw (you can draw all the letters within a single Path2D)
Use a AffineTransform to translate the location of the Graphics and Graphics2D#draw to physically paint the Path2D
Use a Swing Timer to schedule a regular call back within which you can update the position of the Path2D and call repaint on the component to trigger an update
See
Concurrency in Swing
How to use Swing Timers
2D Graphics
for more details
Don't call Thread.sleep or any other blocking process within the paintComponent method (or from within the context of the Event Dispatching Thread) as this will prevent the EDT from updating the screen.
Make sure you are creating/updating your UI only from within the context of the EDT, see Initial Threads for more details

Java House Applet

So I'm just starting with Applets and I am making a house with an open door and 2 open windows when the applet loads. When you click these windows or door then they will shut. My question though is what do I need to do to re-open these windows doors. I figure I need to set the Boolean variables to False somehow and repaint. Where would I do this. I don't need you guys to write the code for me, I just want to know what I should do.
Thanks ahead of time,
Rick
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
/**
Rick Armstrong
Chapter 14 - House Applet
*/
public class HouseApplet extends Applet {
boolean leftWin, rightWin, door;
public void init()
{
leftWin = false;
rightWin = false;
door = false;
setBackground(Color.white);
addMouseListener(new MyMouseListener());
}
public void paint(Graphics g)
{
super.paint(g);
// Draw the house.
g.setColor(Color.black);
g.drawRect(100, 100, 200, 100);
// Draw the roof
g.drawLine(80, 100, 320, 100);
g.drawLine(80, 100, 200, 40);
g.drawLine(200, 40, 320, 100);
// Draw the left window open.
g.fillRect(120, 130, 40, 40);
// Draw the right window open.
g.fillRect(240, 130, 40, 40);
// Draw the door open.
g.fillRect(180, 130, 40, 70);
if (leftWin) {
// Draw the left window closed.
g.setColor(Color.white);
g.fillRect(120, 130, 40, 40);
g.setColor(Color.black);
g.drawRect(120, 130, 40, 40);
g.drawLine(140, 130, 140, 170);
g.drawLine(120, 150, 160, 150);
}
if (rightWin) {
// Draw the right window closed.
g.setColor(Color.white);
g.fillRect(240, 130, 40, 40);
g.setColor(Color.black);
g.drawRect(240, 130, 40, 40);
g.drawLine(260, 130, 260, 170);
g.drawLine(240, 150, 280, 150);
}
if (door) {
// Draw the door closed.
g.setColor(Color.white);
g.fillRect(180, 130, 40, 70);
g.setColor(Color.black);
g.drawRect(180, 130, 40, 70);
g.fillOval(210, 165, 07, 07);
}
}
private class MyMouseListener implements MouseListener
{
public void mousePressed(MouseEvent e)
{
}
public void mouseClicked(MouseEvent e)
{
int currentx = e.getX();
int currenty = e.getY();
boolean WindowLeft = (currentx >= 120 && currentx < 160 && currenty >= 130 && currenty <= 170);
if (WindowLeft)
{
leftWin = true;
repaint();
}
boolean WindowRight = (currentx >= 240 && currentx < 280 && currenty >= 130 && currenty <= 170);
if (WindowRight)
{
rightWin = true;
repaint();
}
boolean Door = (currentx >= 180 && currentx < 220 && currenty >= 40 && currenty <= 200);
if (Door)
{
door = true;
repaint();
}
else;
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
}
}
Maybe I'm misunderstanding the question, but why are you always setting the values to true in the event handler?
If you want a toggling behavior, you could simply write: value = !value and then repaint.
Since you initially set your value to false, the next click would set it to true, the next to false, etc. etc.
For example:
if (WindowLeft)
{
leftWin = !leftWin;
repaint();
}
Note that it is possible for you to cause sort of a "race condition" by clicking faster than the framework has a chance to update the view, but this is usually not a problem for initial problem.
BTW: In terms of readability, consider naming your variables in a way that conveys their meaning. For example, is the naming door evocative of a boolean? not really. but doorOpen is, and it helps interpret the meaning of the variable and its transitions.
if (WindowRight)
{
rightWin = false;
repaint();
}
else {
rightWin = true;
repaint();
}
try the above. When you click inside the window, it closes otherwise it opens

Categories

Resources