Java Tutorial/Trail: Full-Screen Exclusive Mode API

Full-Screen Exclusive Mode API

edit

"Full-Screen Exclusive Mode" is a special mode of the Java graphics system that allows to write to a whole screen, not just to a window. Obviously this mode can be useful to turn a large e-paper display or monitor into a smart board.

Examples

edit

An example smart board in Java

edit

The following code switches the graphics system to full-screen mode.

public void startFullscreen ()
{
        if (!graphicsDevice.isFullScreenSupported ())
        {
            throw new UnsupportedOperationException ("Fullscreen mode is unsupported.");
        }
        jFrame = new JFrame ();
        jFrame.setLayout (new BorderLayout ());
        jFrame.add (new JPanel (), BorderLayout.CENTER);
        jFrame.addKeyListener (new AnyKeyListener ());
        graphicsDevice.setFullScreenWindow (jFrame);
}

public void endFullscreenMode ()
{
        graphicsDevice.setFullScreenWindow (null);
        System.exit (0);
}

The "any key" listener is useful to get you back to your usual desktop. The class implements the KeyListener interface to listen for keyboard events and is registered with the frame as the responsible component for sending these events through the addKeyListener() method in the code above.

private class AnyKeyListener implements KeyListener
{
        public void keyTyped (KeyEvent e)
        {
            endFullscreenMode ();
        }

        public void keyPressed (KeyEvent e)  {}
        public void keyReleased (KeyEvent e) {}
}

Class: Pen

edit

In order to be able to draw on the smart board we need a pen (cvs), which is a class that implements two more listener interfaces: MouseMotionListener and MouseListener.

public class Pen implements MouseMotionListener, MouseListener
{
    private BoardPanel boardPanel;
    private Toolbar toolbar;
    private boolean penDown = false;

    public Pen (BoardPanel boardPanel)
    {
        super ();
        this.boardPanel = boardPanel;
        toolbar = boardPanel.toolbar;
        boardPanel.addMouseListener (this);
        boardPanel.addMouseMotionListener (this);
    }
    
    /* MouseMotionListener */
    
    public void mouseDragged (MouseEvent e)
    {
        if (penDown)
            boardPanel.drawTo (e.getPoint ());
    }

    public void mouseMoved (MouseEvent e) {}

    /* MouseListener */
    
    public void mouseClicked (MouseEvent e) {}
    public void mouseEntered (MouseEvent e) {}
    public void mouseExited  (MouseEvent e) {}

    public void mousePressed (MouseEvent e)
    {
        Point p = e.getPoint ();
        if (p.x > toolbar.margin)
        {
            if (boardPanel.checkWidgetClicked (p))
                return;
        }
        penDown = true;
        boardPanel.startDraw (p);
    }

    public void mouseReleased (MouseEvent e)
    {
        if (!penDown)
            return;
        boardPanel.endDraw (e.getPoint ());
        penDown = false;
    }
}

Class: Glyph

edit

The class Glyph (cvs) represents a connected set of points that have been drawn with a single line onto the smart board, usually a letter or several letters.

public class Glyph
{
    public Point[] points;

    public void paint (Graphics2D g)
    {
        Point p, l = points[0];
        for (int i=1; i < points.length; i++)
        {
            p = points[i];
            g.drawLine (l.x, l.y, p.x, p.y);
            l = p;
        }
    }

    public void paintAt (Graphics2D g, int x, int y)
    {
        Point p, l = points[0];
        for (int i=1; i < points.length; i++)
        {
            p = points[i];
            g.drawLine (l.x + x, l.y + y, p.x + x, p.y + y);            
            l = p;
        }
    }
  
    public void moveRelative (Point to)
    {
        for (int i=0; i < points.length; i++)
        {
            points[i].x += to.x;
            points[i].y += to.y;
        }
    }
    
    public void moveTo (Point origin)
    {
        Point o = getOrigin ();
        origin.x -= o.x;
        origin.y -= o.y;

        for (int i=0; i < points.length; i++)
        {
            points[i].x += origin.x;
            points[i].y += origin.y;
        }
    }

    public Point getOrigin ()
    {
        int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE;
        
        for (int i=0; i<points.length; i++)
        {
            x = Math.min (points[i].x, x);
            y = Math.min (points[i].y, y);
        }
        return new Point (x, y);
    }
    
    public Dimension getSize ()
    {
        Point o = getOrigin ();
        int x = 0, y = 0;
        
        for (int i=0; i<points.length; i++)
        {
            x = Math.max (points[i].x, x);
            y = Math.max (points[i].y, y);
        }
        return new Dimension (x - o.x, y - o.y);
    }
    
    public int lowestPosition ()
    {
        int y = 0;
        for (int i=0; i<points.length; i++)
            y = Math.max (points[i].y, y);
        return y;
    }
}

Input handling

edit

Now the BoardPanel (cvs) methods startDraw() and endDraw() can push points of a line into the input queue, from which glyphs are assembled via the GlyphCache (cvs) class.

protected void startDraw (Point p)
{
        iQueue.pushPoint (p);
}
    
protected void endDraw (Point p)
{
        iQueue.pushPoint (p);
        repaint ();
        iQueue.pushPoint (PEN_UP);
}
...

public class GlyphCache
{
    final static int POINT_BUFFER_SIZE = 0xffff;

    private Point[] points = new Point[POINT_BUFFER_SIZE];
    private int mark;

    public void pushPoint (Point p)
    {
        points[mark++] = p;
    }

    public Glyph getGlyph ()
    {
        Glyph glyph = new Glyph ();
        glyph.points = new Point[mark];
        System.arraycopy (points, 0, glyph.points, 0, mark);
        mark = 0;
        return glyph;
    }
    
    public void paint (Graphics2D gc)
    {
        Point p1, p2 = points[0];
        for (int i=1; i < mark; i++)
        {
            p1 = points[i];
            gc.drawLine (p1.x, p1.y, p2.x, p2.y);
            p2 = p1;
        }
    }
}
edit