JPPF node screensaver
From JPPF 6.2 Documentation
|
Main Page > Customizing JPPF > Node screensaver |
A screensaver can be associated with a running JPPF node. The screensaver is a Java Swing UI which is displayed at the time the node is launched. It can run in full screen or in windowed mode, depending on the configuration settings.
1 Creating a custom screensaver
A screensaver implements the interface JPPFScreenSaver, defined as follows:
public interface JPPFScreenSaver { // Get the Swing component for this screen saver JComponent getComponent(); // Initialize this screen saver, and in particular its UI components void init(TypedProperties config, boolean fullscreen); // Destroy this screen saver and release its resources void destroy(); }
The screensaver lifecycle is as follows:
- the screensaver is instantiated, based on a class name specified in the configuration (requires a no-arg constructor)
- the init() method is called, passing in the JPPF configuration and a flag indicating whether the full screen mode is both requested and supported
- a JFrame is created and the component obtained by calling getComponent() is added to this JFrame. In full screen, the frame is undecorated (no caption, menu bar, status bar or borders) and will cover all available space on all available monitors: the screen saver will spread over all screens in a multi-monitor setup
- the frame is then made visible
- finally, the destroy() method is called when the frame is closed. In full screen mode, this happens upon pressing a key or clicking or (optionally) moving the mouse
The code which handles the screensaver is implemented as a node initialization hook: this means it starts just after the configuration has been read.
Here is a sample screensaver implementation which draws a number of small circles at random locations and with a random color, around 25 times per second. Addtionally, the screen is cleared every 5 seconds and the process starts over:
public class SimpleScreenSaver extends JPanel implements JPPFScreenSaver { private Random rand = new Random(System.nanoTime()); private Timer timer = null; private volatile boolean reset = false; public SimpleScreenSaver() { super(true); } @Override public JComponent getComponent() { return this; } @Override public void init(TypedProperties config, boolean fullscreen) { setBackground(Color.BLACK); timer = new Timer("JPPFScreenSaverTimer"); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { repaint(); } }, 40L, 40L); // draw new circles every 40 ms or 25 times/second timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { reset = true; } }, 5000L, 5000L); // clear the screen every 5 seconds } @Override public void destroy() { if (timer != null) timer.cancel(); } @Override public void paintComponent(final Graphics g) { int w = getWidth(); int h = getHeight(); if (reset) { // if reset requested, clear the screen reset = false; g.setColor(Color.BLACK); g.fillRect(0, 0, w, h); } else { // draw 500 small circles int n = 5; for (int i=0; i<500; i++) { // random x, y coordinates int x = rand.nextInt(w-(n-1)); int y = rand.nextInt(h-(n-1)); // random color g.setColor(new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256))); g.fillOval(x, y, n, n); } } } }
It will look like this:
2 Integrating with node events
To receive notifications of node lifce cycle events and/or individual tasks completion, you will need to implement the NodeIntegration interface or, more conveniently, extend the adapter class NodeIntegrationAdapter. NodeIntegration is defined as follows:
public interface NodeIntegration extends NodeLifeCycleListener, TaskExecutionListener { // Provide a reference to the screen saver void setScreenSaver(JPPFScreenSaver screensaver); }
As we can see, this is just an interface which joins both NodeLifeCycleListener and TaskExecutionListener and provides a way to hook up with the screensaver.
The following example shows how to use node events to display and update the number of tasks executed by the node in the screensaver:
// displays the number of executed tasks in a JLabel public class '''MyScreenSaver''' extends JPanel '''implements JPPFScreenSaver''' { private JLabel nbTasksLabel = new JLabel("number of tasks: 0"); private int nbTasks = 0; @Override public JComponent getComponent() { return this; } @Override public void init(TypedProperties config, boolean fullscreen) { this.add(nbTasksLabel); } @Override public void destroy() { } public void updateNbTasks(int n) { nbTasks += n; nbTasksLabel.setText("number of tasks: " + nbTasks); } } // update the number of tasks on each job completion event public class '''MyNodeIntegration extends NodeIntegrationAdpater''' { private MyScreenSaver screensaver = null; @Override public void jobEnding(NodeLifeCycleEvent event) { if (screensaver != null) screensaver.updateNbTasks(event.getTasks().size()); } @Override public void setScreenSaver(JPPFScreenSaver screensaver) { this.screensaver = (MyScreenSaver) sceensaver; } }
3 Configuration
The screensaver supports a number of configuration properties which allow a high level of customization:
# enable/disable the screen saver, defaults to false (disabled) jppf.screensaver.enabled = true # the screensaver implementation: fully qualified class name of an implementation of # org.jppf.node.screensaver.JPPFScreenSaver jppf.screensaver.class = org.jppf.node.screensaver.impl.JPPFScreenSaverImpl # the node event listener implementation: fully qualified class name of an # implementation of org.jppf.node.screensaver.NodeIntegration # if left unspecified or empty, no listener will be used jppf.screensaver.node.listener = org.jppf.node.screensaver.impl.NodeState # title of the JFrame used in windowed mode jppf.screensaver.title = JPPF is cool # path to the image for the frame's icon (in windowed mode) jppf.screensaver.icon = org/jppf/node/jppf-icon.gif # display the screen saver in full screen mode? # in full screen mode, the screen saver will take all available screen space on all # available monitors, the mouse cursor is not displayed, and the node will exit on any # key pressed, mouse click or mouse motion jppf.screensaver.fullscreen = true # width and height (in pixels), only apply if fullscreen = false. Default to 1000x800 jppf.screensaver.width = 1000 jppf.screensaver.height = 800 # close on mouse motion in full screen mode? default to true jppf.screensaver.mouse.motion.close = true
4 JPPF built-in screensaver
A built-in screensaver is provided, which displays an number of moving small logos (images) bouncing around the screen and bouncing against each other. Additionally, it displays panel comprising a (personalizable) logo, along with a status bar indicating how long the node has been running, its connection status, execution status and the number of tasks it has executed. It looks like this:
The built-in screensaver proposes a number of spceific configuration options, which aim at providing a fine level of personalization and hopefully some fun!
# should collisions between moving logos be handled? defaults to true jppf.screensaver.handle.collisions = true # number of moving logos jppf.screensaver.logos = 50 # speed from 1 to 100 jppf.screensaver.speed = 100 # path to the moving logo image(s). Multiple images can be specified, their paths # must be separated with '|' (pipe) characters. They will be distributed in a # round-robin fashion according to the number of logos jppf.screensaver.logo.path = org/jppf/node/jppf_group_small2.gif| \ org/jppf/node/rectagle_blue.png| \ org/jppf/node/rectagle_orange.png| \ org/jppf/node/rectagle_green.png| \ org/jppf/node/rectagle_red.png # path to the larger image at the center of the screen jppf.screensaver.centerimage = org/jppf/node/jppf@home.gif # horizontal alignment of the status panel (including the larger image). # useful when using a multi-monitor setup, where a centered panel will be split on two # screens and thus more difficult to read # possible values: 'left' or 'l', 'center' or 'c', 'right' or 'r'; default is 'center' jppf.screensaver.status.panel.alignment = center
To use this screensaver, you need to set the following properties:
jppf.screensaver.enabled = true jppf.screensaver.class = org.jppf.node.screensaver.impl.JPPFScreenSaverImpl jppf.screensaver.node.listener = org.jppf.node.screensaver.impl.NodeState
Main Page > Customizing JPPF > Node screensaver |