Skip to main content

Image filtering in Swing applications

2 replies [Last post]
jblumenkrantz
Offline
Joined: 2003-06-10
Points: 0

I have a Swing GUI that performs long blocking RMI calls. These calls are being made in a worker thread to maintain UI responsiveness and to repaint the application, but while the calls are being made I'd like to visually "disable" the application by rendering the entire application frame in grayscale and popping up a modal dialog to alert the user, much like the Restart/Log Off/Shutdown dialog box behaves in Windows XP. Is there a way to intercept the painting of the root frame to perform a global image transformation of this sort on the application?

Thanks in advance
-Jason Blumenkrantz

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jblumenkrantz
Offline
Joined: 2003-06-10
Points: 0

Works perfectly, thanks a lot. Only had to change getContentPane() to getRootPane() to include the menu bar as well. Now I just need to figure out how to predict when the RMI call will take long enough to justify the cost of the extra painting...

Thanks again
-Jason

shan-man
Offline
Joined: 2006-02-17
Points: 0

Hi jblumenkrantz,

One of the great features of Swing is that it does its own painting. A neat thing about this is that you can have components paint to other places than just the screen (say to an image for example). I've used this idea to implement a solution to your question. Here's how it works:

- Right before you show the modal dialog, you grab a snapshot of the whole UI. This is accomplished by creating an image and painting the contentpane to that image.

- Once you've obtained this "snapshot", you can then filter or modify that image however you see fit.

- The last step is to show that new image overtop of the actual UI. Pretty neat effect...you paint a grayed-out image of the UI overtop of the actual thing. It looks like the UI is just grayed-out! In order to show this image, you can install a custom glasspane on your frame that knows how to show images. When you're ready to show the grayed-out version, you give the image to the custom glasspane and tell it to show itself. Quite easy!

Here's the code:

[code]
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

/**
* Example to show how one can make an entire frame's UI
* appear grayed out while showing a modal dialog box.
*
* @author Shannon Hickey
*/
public class GrayGui extends JFrame {

ImageGlassPane gp = new ImageGlassPane();

public GrayGui() {
JButton top = new JButton("Top");
top.setBackground(Color.GREEN);
JButton bottom = new JButton("Gray It!");
bottom.setBackground(Color.RED);
bottom.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
grayItOut();
}
});

getContentPane().add(top, BorderLayout.NORTH);
getContentPane().add(bottom, BorderLayout.SOUTH);
getContentPane().add(new JScrollPane(new JTextArea()), BorderLayout.CENTER);

// replace the default glasspane with one that knows how to paint
// an image
setGlassPane(gp);
}

public static void main(String[] args) {
GrayGui gg = new GrayGui();
gg.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gg.setSize(400, 400);
gg.setLocationRelativeTo(null);
gg.setVisible(true);
}

/**
* Gray out the UI and show a modal dialog box
*/
private void grayItOut() {
// Create a BufferedImage to use in order to snapshot the UI
Image snapshot = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);

// fetch the Graphics from the image
Graphics g = snapshot.getGraphics();

// paint the content pane to the image
getContentPane().paint(g);

// dispose the graphics to free resources
g.dispose();

// use GrayFilter to grey out the image
// *** NOTE, you could manipulate this image however you want
snapshot = GrayFilter.createDisabledImage(snapshot);

// set the image on our custom glasspane
gp.setImage(snapshot);

// show the glasspane
gp.setVisible(true);

// tell the glasspane to paint iteself immediately
// otherwise it won't show until shortly after the modal dialog is shown
gp.paintImmediately(0, 0, getWidth(), getHeight());

// show the dialog box
JOptionPane.showMessageDialog(this, "The frame should now appear grayed.");

// hide the glasspane
gp.setVisible(false);
gp.setImage(null);
}

/**
* We'll use an instance of this as the glasspane. It's a simple
* subclass of JPanel that paints an image.
*/
class ImageGlassPane extends JPanel {
Image image = null;

public void paintComponent(Graphics g) {
if (image != null) {
g.drawImage(image, 0, 0, this);
}
}

public void setImage(Image image) {
this.image = image;
this.repaint();
}
}
}
[/code]

Regards,
Shannon