The Source for Java Technology Collaboration
User: Password:



Joshua Marinacci

Joshua Marinacci's Blog

Swing Hack 7: Let it Snow!

Posted by joshy on December 22, 2003 at 06:11 AM | Comments (3)

I've always wanted to make some sort of display that draws outside of a window with images scattered all across the screen. Though previously impossible in Java, I found a way to do it. And since Christmas is coming up I thought I'd use it to make a snowflake display. Here's a cropped screenshot of what it looks like:


Snowfall Screenshot (click for fullsize)

Okay. I lied. I didn't really find a way to draw outside of a JFrame. It's impossible without native code. However, we can make a really nice fake. While searching on the internet (I love how anything can be explained with 'while I was searching on the internet') I came across an example of making transparent windows. It seems that the Robot class has the ability to take a screen capture. Combined with fullscreen mode we can pretend that we have the ability to draw all over the screen outside of frame boundaries.

Here's the basic idea: Take a screenshot. Switch to fullscreen mode. Make a panel that covers the whole screen. Draw the screenshot onto the panel. Draw what we want on top of the panel. Voilia, we can pretend to draw anywhere on the screen.

This is longer than any of my previous hacks, so I'll go through just the important bits and then let you download the code.

This makes a screen capture:

public static void captureScreen() throws AWTException {
    Robot robot = new Robot();
    Toolkit tk = Toolkit.getDefaultToolkit();
    size = tk.getScreenSize();
    Rectangle bounds = new Rectangle(0,0,(int)size.getWidth(),(int)size.getHeight());
    screen = robot.createScreenCapture(bounds);
}

This switches to full screen mode:

public static JFrame goFullScreen() {
    GraphicsEnvironment env = GraphicsEnvironment.
        getLocalGraphicsEnvironment();
    device = env.getDefaultScreenDevice();
    original_mode = device.getDisplayMode();
    JFrame frame = new JFrame(device.getDefaultConfiguration());
    frame.setUndecorated(true);
    frame.setResizable(false);
    device.setFullScreenWindow(frame);
    return frame;
}

This switches back to normal mode:

public static void goNormalScreen() {
    device.setDisplayMode(original_mode);
    device.setFullScreenWindow(null);
}

This initializes all of the snowflake variables with random values. It lets us control how far away the flakes are, how fast they fall, and how much they twitter from side to side.


    points = new Point[num_flakes];
    pointimages = new Image[num_flakes];
    rates = new int[num_flakes];
    distances = new int[num_flakes];
    for(int i=0; i<points.length; i++) {
        // create a new point
        points[i] = new Point(-1,-1);
        // set a random distance
        distances[i] = 1+(int)(Math.random()*max_distance);
        // set the fallrate to be inversely proportional to the distance
        rates[i] = 1+(int)(fall_rate/distances[i]);
        // randomly choose one of the images;
        pointimages[i] =
            snowflake_source[(int)(Math.random()*8)];
    }

This runs in a separate thread to update each snowflake. We respawn only on every 10th loop, and only if there is a slot free for a new flake. Maybe this would be better with growable vectors or a queue.

public void run() {
    go = true;
    int spawncount = 0;
    while(go) {
        spawncount++;
        // sleep for 100 milliseconds
        try { Thread.sleep(20); } catch (Exception ex) { }
        // loop over each point and move it if appropriate
        for(int i=0; i<points.length; i++) {
            Point pt = points[i];
            // if it's a dead snowflake
            if(pt.y <0 ) {
                // only respawn on every 10th time through the loop
                if(spawncount%10==0) {
                    pt.y = 10;
                    pt.x = (int) (Math.random() * size.getWidth());
                    spawncount++;
                }
                continue;
            }

            // if at the bottom of the screen the kill it
            if(pt.y > screen.getHeight()) {
                pt.y = -1;
                continue;
            }

            // for all normal snowflakes
            // move each point down
            points[i].y = points[i].y + rates[i];
            // move randomly to the right or left
            points[i].x += (int)(5*(0.5-Math.random()));
        }
        // respawn it if needed
        repaint();
    }
}

This does the actual painting.

public void paintComponent(Graphics g) {
    g.drawImage(screen,0,0,null);

    for(int i=0; i<points.length; i++) {
        if(points[i].y > 0) {
            double w= pointimages[i].getWidth(null);
            double h = pointimages[i].getHeight(null);
            // dist = 0 w = w*1
            // dist = 20 w = w*1/20
            w = w * 1/this.distances[i];
            h = h * 1/this.distances[i];
            g.drawImage(pointimages[i], points[i].x+20, points[i].y+20, (int)w, (int)h ,null);
        }
    }
}

I'm sure you could all imagine more realistic algorithms for doing it, but this will just draw the flakes larger and smaller based on the distance. If we wanted to we could start using affine transforms to make the flakes spin and rotate.

Here's a zipfile with the code and images.

Happy Holidays everyone. I'm out until next year!


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • i went some help
    Hi
    i dont like formal protocols in writing letters so apologize me for this
    first i went to thank you for the informative topic you published about the Robot class
    and its capabillities in capturing desktop images and initiating events

    i still novice in java but am facing a greate problem my instructor went from me a remote access client server application
    i realy will thank you very much if you send me a detailed description with examples
    about the way to use this class

    at last i went to thank you for replayiong me
    thanks

    Posted by: wassim_1983 on March 25, 2004 at 12:45 AM

  • i went some help
    Hi
    i dont like formal protocols in writing letters so apologize me for this
    first i went to thank you for the informative topic you published about the Robot class
    and its capabillities in capturing desktop images and initiating events

    i still novice in java but am facing a greate problem my instructor went from me a remote access client server application
    i realy will thank you very much if you send me a detailed description with examples
    about the way to use this class

    at last i went to thank you for replayiong me
    thanks

    Posted by: wassim_1983 on March 25, 2004 at 12:47 AM

  • i went some help
    Hi
    i dont like formal protocols in writing letters so apologize me for this
    first i went to thank you for the informative topic you published about the Robot class
    and its capabillities in capturing desktop images and initiating events

    i still novice in java but am facing a greate problem my instructor went from me a remote access client server application
    i realy will thank you very much if you send me a detailed description with examples
    about the way to use this class

    at last i went to thank you for replayiong me
    thanks
    Wassim

    Posted by: wassim_1983 on March 25, 2004 at 12:48 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds