We have opened the Nimbus project on http://nimbus.dev.java.net/ to the public so you can go there and get the source or sign up to help out
Posted on Mar 12, 2007
Nimbus project open to the public
Posted on Mar 9, 2007
Nimbus & Desktop Matters
I am sitting here at Desktop Matters conference which is fab. Now that Nimbus has been announced I can blog on it. Nimbus is a new Look and Feel designed by Sun which is going to be avilable in future versions of Solaris and there are a group of us making a pure Java implementation with the aim of making a modern cross platform look and feel. The aim is for Nimbus to support Java 1.5 and newer and based on Synth as far as possible.Nimbus is going to be a public opensource project at java.net and will be available very shortly. Ben Galbraith has some of the design mockups on his blog.As a taster here are a couple screenshots of SwingSet running Nimbus L&F.


Posted on May 23, 2005
Swing Listeners and Threads…
How do you listen? I end up writing a couple of the addListenerX(), removeListenerX(), fireEventX() patterns every day almost. There are a couple of ways around to implement this with an ArrayList or maybe a HashSet or the AWTEventMulticaster. Generaly I have ended up with one of the first two for ease of implementation. A couple days a go I got the dreaded ConcurrentModificationException which when traced down was caused buy a well known problem of trying to add/remove a listener from inside the fire event method. AWTEventMulticaster is one possible solution checkout Java World Article for an example, but this ends up with a lot of code for such a every day operation. After a bit of a dig around the new Java 1.5 concurrent classes I came up on CopyOnWriteArraySet which looks to fit my problem perfectly. Fast synchronization free firing of events, thread safe add/remove and simple code use. So I end up with:
    public interface IListenerX {
        public void xHasHappened();
    }
    private CopyOnWriteArraySet m_oListeners = new CopyOnWriteArraySet;
   Â
    public void addListenerX(IListenerX i_oListenerX){
        m_oListeners.add(i_oListenerX);
    }
   Â
    public void removeListenerX(IListenerX i_oListenerX){
        m_oListeners.add(i_oListenerX);
    }
   Â
    private void fireXHasHappened(){
        for (IListenerX oListenerX : m_oListeners) {
            oListenerX.xHasHappened();
        }
    }
After having a little web search with the new found idea I came across PropertyChangeMulticaster by Doug Lea which is a custom CopyOnWriteArraySet implementation for bean property events. If Doug Lea says it?s the way to go then I have got to be onto the right thing? What are you using?
Posted on May 3, 2005
Java/Swing can be as fast as native!
I have been experimenting with java today seeing if Java is fast enough to make a full-screen slideshow application that fades between images. The answer is Yes well at least on Windows with the right -D switches. It is using “Full-Screen Exclusive Mode” with two off-screen buffers and page switching. Let me know if you try it on OS X or Linux and how it runs and if there are any -D system properties that help. I think the definitive list for Java2D -D switches is here. So try it out and tell me what you think, it requires at least Java 1.5.
- Windows Exe (Sets all the properties for you)
- Jar File (run with “java -Dsun.java2d.ddscale=true -Dsun.java2d.ddforcevram=true -Dsun.java2d.translaccel=true -cp SlideShowApp.jar SlideShowApp”)
- Java Source
// ==============================================================================
// Example Java Slide Show Applications
// Copyright: Jasper Potts 2005
// ==============================================================================
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.event.MouseInputAdapter;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.MouseEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;
public class SlideShowApp {
private static List IMAGES = new ArrayList();
Frame mainFrame;
GraphicsConfiguration gc = null;
public SlideShowApp(int numBuffers, GraphicsDevice device) {
try {
gc = device.getDefaultConfiguration();
mainFrame = new Frame(gc);
mainFrame.addMouseListener(new MouseInputAdapter() {
@Override public void mouseClicked(MouseEvent e) {
System.exit(0);
}
});
mainFrame.setUndecorated(true);
mainFrame.setIgnoreRepaint(true);
device.setFullScreenWindow(mainFrame);
Rectangle bounds = mainFrame.getBounds();
mainFrame.createBufferStrategy(numBuffers);
BufferStrategy bufferStrategy = mainFrame.getBufferStrategy();
BufferedImage oTranslucentImage = gc.createCompatibleImage(bounds.width,
bounds.height, Transparency.TRANSLUCENT);
BufferedImage oImage = loadScaled(IMAGES.get(0), bounds.width, bounds.height);
BufferedImage oNextImage;
for (int iImageIndex = 0; iImageIndex < (IMAGES.size() - 1); iImageIndex++) {
oNextImage = null;
for (float a = 1; a <= 10; a += 0.75) {
Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
if (!bufferStrategy.contentsLost()) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, bounds.width, bounds.height);
if (oNextImage == null) {
oNextImage = loadScaled(IMAGES.get(iImageIndex + 1), bounds.width, bounds.height);
Graphics2D g2 = oTranslucentImage.createGraphics();
g2.setColor(new Color(0, 0, 0, 255));
g2.fillRect(0, 0, bounds.width, bounds.height);
g2.drawImage(oNextImage,
(bounds.width - oNextImage.getWidth()) / 2,
(bounds.height - oNextImage.getHeight()) / 2, null);
g2.dispose();
}
g.drawImage(oImage,
(bounds.width - oImage.getWidth()) / 2,
(bounds.height - oImage.getHeight()) / 2, null);
float fAlpha = (float) Math.log10(a);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, fAlpha));
g.drawImage(oTranslucentImage,
(bounds.width - oTranslucentImage.getWidth()) / 2,
(bounds.height - oTranslucentImage.getHeight()) / 2, null);
bufferStrategy.show();
g.dispose();
}
try {
Thread.sleep((a == 1) ? 2000 : 1);
} catch (InterruptedException e) {}
}
oImage = oNextImage;
}
} catch (Exception e) {
e.printStackTrace();
device.setFullScreenWindow(null);
JOptionPane.showMessageDialog(null, "Error \"" + e.getMessage() + "\"",
"Error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
} finally {
device.setFullScreenWindow(null);
}
}
public BufferedImage loadScaled(File i_oImageFile, int i_iWidth, int i_iHeight) throws Exception {
BufferedImage oImage = ImageIO.read(i_oImageFile);
double dScale = calculateScaleFactor(oImage.getWidth(), oImage.getHeight(), i_iWidth, i_iHeight);
if (dScale < 1) {
int iWidth = (int) (oImage.getWidth() * dScale);
int iHeight = (int) (oImage.getHeight() * dScale);
BufferedImage oScaledImage = gc.createCompatibleImage(iWidth, iHeight);
Graphics2D g = oScaledImage.createGraphics();
g.drawImage(oImage, 0, 0, iWidth, iHeight, null);
g.dispose();
return oScaledImage;
} else {
return oImage;
}
}
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFileChooser oFileChooser = new JFileChooser();
if (args.length > 0) oFileChooser.setSelectedFile(new File(args[0]));
oFileChooser.setDialogTitle("Select a directory containing jpeg images");
oFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (oFileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
// scan for images
findImages(oFileChooser.getSelectedFile());
if (IMAGES.size() == 0) {
JOptionPane.showMessageDialog(null, "No jpeg images found in \"" + oFileChooser.getSelectedFile() +
"\"",
"No Images Found", JOptionPane.ERROR_MESSAGE);
} else {
// do slideshow
int numBuffers = 2;
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = env.getDefaultScreenDevice();
new SlideShowApp(numBuffers, device);
}
}
}
private static void findImages(File i_oFile) {
if (i_oFile.isDirectory()) {
File[] oChildren = i_oFile.listFiles(new FileFilter() {
public boolean accept(File i_oFile) {
return (i_oFile.isDirectory()) || (i_oFile.getName().toLowerCase().endsWith(".jpg"));
}
});
for (int i = 0; i < oChildren.length; i++) {
findImages(oChildren[i]);
}
} else {
IMAGES.add(i_oFile);
}
}
public static final double calculateScaleFactor(int i_iSrcWidth, int i_iSrcHeight, int i_iReqWidth,
int i_iReqHeight) {
double dXscale = (double) i_iReqWidth / (double) i_iSrcWidth;
double dYscale = (double) i_iReqHeight / (double) i_iSrcHeight;
return Math.min(dXscale, dYscale);
}
}