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 Digg DZone Furl 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
|