Swing Rocks - A Tribute to Filthy Rich Clients Pär Sikö, Martin Gunnarsson Epsilon Information Technology
One way that Pollak has found to speed up JavaTM programs is to rewrite their user interfaces in Microsoft's Visual Basic. 2
Sure it looks like shit, but at least it does so consistently on all operating systems. 3
and that's why Java on the desktop is as dead as an Egyptian mummy.
How bad can it possibly be? 5
What s the problem? 9
10
11
The Swing Rocks Formula Subtle effects Smooth animations Custom components Good performance 12
Demo: Feedjii 13
Under the hood 14
15
16
17
paint(graphics g) paintcomponent(graphics g) paintborder(graphics g) paintchildren(graphics g) 18
19
Feed component 20
public class FeedComponent extends JComponent { private String headline, text; public FeedComponent(String title, String text) { this.headline = title; this.text = text; } @Override protected void paintcomponent(graphics g) { // Paint code goes here } } 21
Graphics2D g2 = (Graphics2D) g; // Enable antialiasing g2.setrenderinghint(renderinghints.key_antialiasing, RenderingHints.VALUE_ANTIALIAS_ON); 22
// Create gradient paint Point top = new Point(0, 0); Point bottom = new Point(0, getheight()); Color topcolor = new Color(192, 192, 192); Color bottomcolor = new Color(95, 95, 95); Paint paint = new GradientPaint(top, topcolor, bottom, bottomcolor); // Set paint g2.setpaint(paint); 23
// Draw background int radius = 10; g2.fillroundrect(0, 0, getwidth(), getheight(), radius, radius); 24
// Draw headline g2.setpaint(color.black); g2.drawstring(this.headline, 15, 15); // Draw body g2.drawstring(this.text, 15, 40); JavaOne The conference where all the cool people hang out 25
What about animations? 26
Timing Framework public class AnimationExample implements TimingTarget { public void createanimation() { Animator animator = new Animator(2000, this); animator.setresolution(10); animator.setacceleration(0.3f); animator.setdeceleration(0.3f); animator.start(); } @Override public void timingevent(float progress) { // Update and redraw } } 27
Step 4: Timing event (Called multiple times) Move the list Step 3: Mouse button released Calculate total distance to scroll Step 2: Mouse dragged (Called multiple times) Update component position Step 1: Mouse button pressed Save start time Save vertical position 28
Kinetic Scrolling public class KineticScrolling extends JComponent implements MouseListener, MouseMotionListener, TimingTarget { private private private private private private private JComponent componenttoscroll; Animator animator; long starttime; int startposition; int distancetoscroll; MouseEvent previousmouseevent; final int animationduration = 1300; 29
Kinetic Scrolling public KineticScrolling(JComponent component) { setlayout(null); addmouselistener(this); addmousemotionlistener(this); componenttoscroll = component; add(componenttoscroll); } 30
Kinetic Scrolling @Override public void mousepressed(mouseevent e) { starttime = System.currentTimeMillis(); startposition = componenttoscroll.gety(); previousmouseevent = e; } 31
Kinetic Scrolling @Override public void mousedragged(mouseevent e) { int diff = e.getyonscreen() previousmouseevent.getyonscreen(); int newyposition = componenttoscroll.gety() + diff; componenttoscroll.setlocation(0, newyposition); previousmouseevent = e; repaint(); } 32
Kinetic Scrolling @Override public void mousereleased(mouseevent e) { int ydiff = componenttoscroll.gety() - startposition; double elapsedtime = System.currentTimeMillis() starttime; double speed = ydiff / elapsedtime; distancetoscroll = (int) (speed * animationduration); startposition = componenttoscroll.gety(); animator = new Animator(animationDuration, this); animator.setresolution(0); animator.setdeceleration(1); animator.start(); } 33
Kinetic Scrolling @Override public void timingevent(float progress) { int newy = (int)(startposition + distancetoscroll * progress); componenttoscroll.setlocation(0, newy); repaint(); } 34
Demo: Kinetic scrolling 35
Performance: Five steps to success 36
1. Hardware Acceleration Flags > > -Dsun.java2d.opengl=true -Dsun.java2d.d3d=true java -Dsun.java2d.opengl=true Feedjii 37
2. Timing issues public class CustomTimer extends TimingSource { private long resolution; private boolean stop = false; public void start() {... } public void stop() { stop = true; } public void setresolution(int resolution) { this.resolution = resolution; } } 38
2. Timing issues continued public void start() { new Thread() { public void run() { while (!stop) { try { sleep(resolution); } catch (Exception e) { } timingevent(); } } }.start(); } 39
3. Cache is king protected void paintcomponent(graphics g) { if(cachedimage == null) { cachedimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = (Graphics2D) cachedimage.getgraphics(); // Paint your component on the cachedimage graphics.drawline(10, 10, 100, 100); } g.drawimage(cachedimage, 0, 0, null); } 40
4. Compatible Images // Regular buffered image cachedimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // Compatible image GraphicsConfiguration conf = getgraphicsconfiguration(); cachedimage = conf.createcompatibleimage(width, height); 41
5. Avoid unnecessary transparency cachedimage = conf.createcompatibleimage(width, height, Transparency.TRANSLUCENT); cachedimage = conf.createcompatibleimage(width, height, Transparency.OPAQUE); 42
Performance summary 250 200 1 50 1 00 50 0 S tandard D 3D OpenG L C ache C ached compatible 43
Summary 44
What s next? www.swing-rocks.com 45
Books 46
Questions 47
Pär Sikö, Martin Gunnarsson www.swing-rocks.com per.siko@epsilon.nu martin.gunnarsson@epsilon.nu 48