LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-10-2012, 05:39 PM   #1
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Rep: Reputation: 23
Java: Random Delay between repaint()


Hi,

I would like to include a random delay or wait between repaint() function calls. The reason for this is to create a delay between a player's move and the machine's move so as to create the illusion that the machine "is thinking".

In the code below, when the user clicks on the panel, two squares are drawn, one where s/he has clicked, the other slightly above. I'd like the square above to appear between 1000ms and 3500ms after the click (the square in the click location to appear immediately). For the time being, they appear at the same time. If someone could alter this code so that it does what I want, I think I'll understand what needs to be done in my actual program:

Code:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.Timer;

public class RepaintDelayTest {
    public static void main(String[] args) {
        MouseFrame frame = new MouseFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

class MouseFrame extends JFrame {
    public MouseFrame() {
        setTitle("MouseTest");
        setSize(300, 300);
        MousePanel panel = new MousePanel();
        add(panel);
    }
}

/**
 * A panel with mouse operations for adding and removing squares.
 */
class MousePanel extends JPanel {
    public MousePanel() {
        squares = new ArrayList<Rectangle2D>();
        current = null;

        addMouseListener(new MouseHandler());
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        // draw all squares
        for (Rectangle2D r : squares)
            g2.draw(r);
    }

    /**
     * Finds the first square containing a point.
     * @param p a point
     * @return the first square that contains p
     */
    public Rectangle2D find(Point2D p) {
        for (Rectangle2D r : squares) {
            if (r.contains(p))
                return r;
        }
        return null;
    }

    /**
     * Adds a square to the collection.
     * @param p the center of the square
     */
    public void add(Point2D p) {
        double x = p.getX();
        double y = p.getY();

        current = new Rectangle2D.Double(x - 10 / 2,
                y - 10 / 2, 10, 10);
        squares.add(current);
        repaint();
    }

    private ArrayList<Rectangle2D> squares;
    private Rectangle2D current;

    private class MouseHandler extends MouseAdapter {
        public void mousePressed(MouseEvent event) {
            
            // add a new square if the cursor isn't inside a square
            Point p = event.getPoint();
            current = find(p);
            if (current == null){
                add(p);
    
                // Add yet another square, slightly above (in actual program this will be the machine's move)
                int x = (int) p.getX();
                int y = (int) p.getY() - 20;
                /* I want a random sleep of between 1000ms and 3500ms between the two "repaint()'s" 
                 (the repaints are in the add function). This represents the machine move in a game.
                 I want to give the user the impression that the machine needs to think before
                 making a move... */
                Random generator = new Random();
                int delay = 0;
                do{
                    delay = generator.nextInt(3500);
                } while (delay < 1000);
                //Timer sleep = new Timer(delay, ???);
                Point p2 = new Point(x, y);
                add(p2);
            }
        }
    }
}
I posted a similar message here (see the very last message for a working example) which was resolved, but which used buttons, not a simple repaint().

Thanks in advance,

rm
 
Old 11-11-2012, 08:05 AM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,455

Rep: Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842
It's not a good idea to delay calls to repaint() because repaint() may be called by things outside of your control, eg: the window being covered and then uncovered. Furthermore, since repaint() only sends a request to call paint(), the call to repaint() after the first square is added will always cause the second square to shown, since you are adding it before before paint() has a chance to be called.

Instead, try delaying the call to add().
Also:
Code:

                int delay = 0;
                do{
                    delay = generator.nextInt(3500);
                } while (delay < 1000);
                int delay = generator.nextInt(2500) + 1000;
 
Old 11-11-2012, 02:36 PM   #3
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
Thank you ntubski for your reply. But I'm having trouble understanding what you are saying. I don't want to know what not to do, I want to know what to do!

In the code example, the repaint() function is in the add() function, so when I say I want to delay the repaint() function, I actually mean delay the add() function which contains the repaint() function.

In any case, I don't really care how it is does, it's the result that counts.

The barred out code in your example/quote corresponds to a few lines just to stock the random delay time in a variable (between 1 and 3.5 seconds), it has nothing to do with an actual delay(), sleep() or wait() function. I named it "delay", but I could have named it "i" or anything.

Would you know how to alter my code to get it to do what I want it to do?

If not, any other takers?

I'm really stuck. I don't know where to start or how to do this, hence the post.

Many thanks,

rm
 
Old 11-12-2012, 10:31 AM   #4
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,455

Rep: Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842
Quote:
I don't want to know what not to do, I want to know what to do!
Code:
               //Timer sleep = new Timer(delay, ???);
                Point p2 = new Point(x, y);
                add(p2);
What you need to do is replace the "???" with an object whose actionPerformed() method will do the equivalent of add(p2). Then call start() on the timer.

Quote:
I posted a similar message here (see the very last message for a working example) which was resolved, but which used buttons, not a simple repaint().
It doesn't really matter if buttons are involved or not. The main difference is here you will need to call add(), there you needed to call setText().

Quote:
The barred out code in your example/quote corresponds to a few lines just to stock the random delay time in a variable (between 1 and 3.5 seconds), it has nothing to do with an actual delay(), sleep() or wait() function.
Right, that was just a suggestion to generate the delay time without using a loop.
 
Old 11-12-2012, 01:46 PM   #5
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
ntubski,

Quote:
What you need to do is replace the "???" with an object whose actionPerformed() method will do the equivalent of add(p2). Then call start() on the timer.
Yup, I know. That's exactly what I don't know how to do, hence my initial post.

I'm not all that great at event handling yet and this is mouse stuff, not other actions.

In the other thread, the ButtonTextSetter was used, which is a Java class.

I really don't know how to do this. I don't even know where to start!

Thanks nevertheless,

rm
 
Old 11-12-2012, 01:51 PM   #6
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
Mea culpa...

I just realized that the ButtonTextSetter class is not a Java class... Give me a little time... I'll try to figure it out...

Sorry about the confusion,

rm
 
Old 11-14-2012, 04:45 AM   #7
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
Okay, yesterday I was ready to give up completely and today I got an idea, but I don't know how to implement it, I really don't. It's probably not the way to go anyway, but here it is...

In the class which is the equivalent of the ButtonTextSetter class of this post I will create a similar class which hides the Rectangle2D object. It will then appear a random number of seconds afterwards.

Code:
    class MachineRectangleTool implements ActionListener {
        final Rectangle2D rectangle;

        MachineRectangleTool(Rectangle2D rectangle) {
            // rectangle.function()?? // make rectangle disappear (hidden or transparent)
            this.rectangle = rectangle;
        }

         private AlphaComposite makeComposite(float alpha) {
              int type = AlphaComposite.CLEAR;
              return(AlphaComposite.getInstance(type, alpha));
             }
        
        public void actionPerformed(ActionEvent ae) {
            // make rectangle appear (show or border color = black)
        }
    }
Another problem I don't know how to tackle is ActionListener / MouseListener, etc... Also, the ButtonTextSetter example has two buttons. The added rectangles in my example must be conserved and accumulate with each repaint().

I'm sorry if it seems that I'm looking for someone to code for me, but it really isn't the case! I really don't know how to solve this problem and code talks to me more than explanations...

The code provided in this message is probably way off, not the ideal solution... Could someone alter my original code to make it do what I want it to do?

Many thanks for your patience,

rm
 
Old 11-14-2012, 10:12 AM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,455

Rep: Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842
Quote:
Another problem I don't know how to tackle is ActionListener / MouseListener, etc...
I'm not sure what problem you're referring to here.

Quote:
The added rectangles in my example must be conserved and accumulate with each repaint().
That is already handled by the add() method.

You're overthinking this.

In the previous example we needed to delay the setText() function call, here we need to delay the add() function call.

In the previous example the parameters to setText() were button2 and "O" (yes, the object we invoke the method on is effectively a parameter to the function). In this example the parameters are the MousePanel instance and p2. Since MouseHandler is a nested class the use of the MousePanel instance is implicit/hidden/obfuscated.

In the previous example we pass the parameters (button2 and "O") to the constructor of ButtonTextSetter and setText() is called in the actionPerformed() method. In this example we will need to pass the parameters (MousePanel instance and p2) to the constructor of MachineRectangleTool (or equivalent, probably a different name should be used as there will be no rectangles involved) and call add() in the actionPerformed() method. You can refer to the MousePanel instance from inside MouseHandler as MousePanel.this.

Quote:
I'm sorry if it seems that I'm looking for someone to code for me, but it really isn't the case! I really don't know how to solve this problem and code talks to me more than explanations...
I hope you don't take this the wrong way, but it seems to me that the code is talking to you much less than you think. I just don't believe a code example is going to help you that much.
 
Old 11-14-2012, 06:15 PM   #9
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
Thanks for your efforts ntubski.

Please forgive me, but all of this is way over my head.

Sincerely,

rm
 
Old 11-15-2012, 06:19 PM   #10
rm_-rf_windows
Member
 
Registered: Jun 2007
Location: Europe
Distribution: Ubuntu
Posts: 205

Original Poster
Rep: Reputation: 23
ntubski,

Quote:
I hope you don't take this the wrong way, but it seems to me that the code is talking to you much less than you think.
You are right! Well, half right. I hadn't even realized that ButtonTextSetter was not a Java class at one point, which is proof that the code wasn't talking to me enough. I would not have been able to make all of this work without your last post (especially the MousePanel.this bit and the fact that I had to actually incude an instance of MousePanel in my class). I followed your recipe and it worked! However I say "half right" because following your recipe hasn't yet taught me the workings of this little program, I'm still going to have to study the two examples carefully. I suppose the code will talk to me if I listen!

Here's the code:

Code:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.Timer;

public class RepaintDelayTest {
    public static void main(String[] args) {
        MouseFrame frame = new MouseFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

class MouseFrame extends JFrame {
    public MouseFrame() {
        setTitle("MouseTest");
        setSize(300, 300);
        MousePanel panel = new MousePanel();
        add(panel);
    }
}

/**
 * A panel with mouse operations for adding and removing squares.
 */
class MousePanel extends JPanel {

    private ArrayList<Rectangle2D> squares;
    private Rectangle2D current;
    private Rectangle2D current2;

    public MousePanel() {
        this.squares = new ArrayList<Rectangle2D>();
        this.current = null;
        this.current2 = null;
        addMouseListener(new MouseHandler());
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        // draw all squares
        for (Rectangle2D r : squares)
            g2.draw(r);
    }

    /**
     * Finds the first square containing a point.
     * 
     * @param p
     *            a point
     * @return the first square that contains p
     */
    public Rectangle2D find(Point2D p) {
        for (Rectangle2D r : squares) {
            if (r.contains(p))
                return r;
        }
        return null;
    }

    /**
     * Adds a square to the collection.
     * 
     * @param p the center of the square
     */
    public void add(Point2D p) {
        double x = p.getX();
        double y = p.getY();

        current = new Rectangle2D.Double(x - 10 / 2, y - 10 / 2, 10, 10);
        squares.add(current);
        repaint();
    }

    private class MouseHandler extends MouseAdapter {
        public void mousePressed(MouseEvent event) {

            // add a new square if the cursor isn't inside a square
            Point p = event.getPoint();
            current = find(p);
            if (current == null) {
                add(p);

                int x = (int) p.getX();
                int y = (int) p.getY() - 20;
                
                Point p2 = new Point(x, y);
                Random generator = new Random();
                int delay = generator.nextInt(2500) + 1000;

                Point2Tool p2tool = new Point2Tool(MousePanel.this, p2);
                Timer sleep = new Timer(delay, p2tool);
                sleep.setRepeats(false);
                sleep.restart();
            }
        }
    }

    class Point2Tool implements ActionListener {
            final MousePanel mousePanel;
            final Point p2;
            
        Point2Tool(MousePanel mousePanel, Point p2) {
            this.mousePanel = mousePanel;
            this.p2 = p2;
        }
        
        public void actionPerformed(ActionEvent ae) {
            MousePanel.this.add(p2);
        }
    }
}
Thank you so much for your patience and perseverance.

If you have any comments about the details of the above code, I'm all ears.

Thanks again!

rm
 
Old 11-15-2012, 08:34 PM   #11
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian
Posts: 2,455

Rep: Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842Reputation: 842
Good to see you didn't give up after all.

Since you made Point2Tool a nested class of MousePanel, you don't need the mousePanel field (and indeed, that field is unused). It might be instructive to rewrite the program without using nested classes.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
JAVA: Popup menu in diffrent class then main Applet, how to repaint()? Valkyrie_of_valhalla Programming 2 10-24-2009 03:14 PM
Java GUI and repaint() problem Cyhaxor Programming 4 03-05-2009 06:51 PM
3 minute delay with socket in java mcnalu Slackware 1 09-24-2008 02:08 AM
Java - repaint on tabbedpane hunterfighter Programming 7 09-25-2006 06:46 AM
Delay on Frame Repaint in kwin... the.jxc Linux - General 0 08-03-2003 08:52 PM


All times are GMT -5. The time now is 04:49 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration