Skip to main content

SideBarFX

Posted by malenkov on March 18, 2009 at 6:00 AM PDT

Fullscreen mode and transparent windows are supported in JavaSE 6 since update 10. I have developed the SideBar example for the JavaOne 2008 by using proprietary Java API to create translucent window that slides out of the right side of the screen. Now I am ready to show the SideBar example created by using the JavaFX API only.

Let's create a fullscreen window first. In the current implementation such windows can be opaque only. By this reason this window cannot be used as a SideBar, but its width and height will be further used.

def screen = Stage {
  fullScreen: true
}

You should wait until the window appears in order to initialize its dimensions. As soon as the window's height becomes greater than 0, you can close the window and use its dimensions to initialize the main window. Note that if the auxiliary fullscreen window is closed before the main window is shown up, the application terminates.

def height = bind screen.height on replace {
  if (height > 0) {
    screen.close();
    // initialize main stage
    ...
  }
}

The main window contains the following content.

The base of the window is a translucent shape intended for processing of mouse events. This shape is based on a rectangle, whose left edge is a cubic curve instead of a line. Note that the shape of the window is not set, because JavaFX has no appropriate API. Besides, shaped windows do not support anti-aliasing.

        Path {
          fill: COLOR
          opacity: OPACITY
          elements: [
            MoveTo {
              x: stage.width
            }
            HLineTo {
              x: offset
            }
            CubicCurveTo {
              x: offset   controlX1: x1   controlX2: x2
              y: height   controlY1: y1   controlY2: y2
            }
            HLineTo {
              x: stage.width
            }
          ]
        }

The left edge of the shape is set off with a thick opaque cubic curve, whose parameters match those of the basic shape.

        CubicCurve {
          fill: null
          stroke: COLOR
          strokeWidth: 4
          startX: offset
          endX: offset   controlX1: x1   controlX2: x2
          endY: height   controlY1: y1   controlY2: y2
        }

Drawn over the shape is the rotated translucent text. Although the text has the same color and opacity as the basic shape, the text looks less transparent, because the opacity values are summed up.

        Text {
          content: "JavaFX"
          opacity: OPACITY
          fill: COLOR
          font: Font {size: 220}
          scaleY: 0.8
          translateX: 240
          translateY: height
          transforms: Rotate {angle: 270}
        }

The close button is drawn in the right top corner of the main window.

        Group {
          translateX: stage.width - 22
          translateY: 22
          cursor: Cursor.HAND
          content: [
            Circle {
              fill: COLOR
              opacity: OPACITY
              radius: 8
            }
            Line {
              stroke: COLOR
              strokeWidth: 4
              strokeLineCap: ROUND
              startX: -4   endX:  3
              startY: -4   endY:  3
            }
            Line {
              stroke: COLOR
              strokeWidth: 4
              strokeLineCap: ROUND
              startX: -4   endX:  3
              startY:  3   endY: -4
            }
          ]
          onMouseClicked: function(event) {
            stage.close()
          }
        }

The logo of Sun Microsystems is added to the center of the window. The clock widget from my first post about JavaFX is added over the logo. Note that the paused variable of the clock widget is bound to the visible variable. Thus you do not waste the processor time to update the hidden clocks.

        ImageView {
          translateX: stage.width - 142
          translateY: 224
          image: Image {
            url: "{__DIR__}sun.png"
          }
        }
        Clock {
          translateX: stage.width - 222
          translateY: 22
          paused: bind not visible
          radius: 100
          fill: COLOR
        }

The SideBar slides out when the mouse cursor hovers over the SideBar content and slides in when the mouse cursor leaves the window.

def slide = Timeline {
  keyFrames: [
    at (0s) {stage.x => screen.width - stage.width}
    at (1s) {stage.x => screen.width - stage.width / 10}
  ]
}
var visible = bind group.hover on replace {
  slide.rate = if (visible) -1 else 1;
  slide.play()
}

This approach has a couple of disadvantages. First, JavaFX has no API to keep the window on top of other windows even if it has the focus. Second, the closed fullscreen window does not receive events on the screen resolution changes. Therefore the SideBar will work incorrectly when the resolution changes.

Note that the application is signed and requires all permissions to slide out off the screen. The source file of the example is available.

Related Topics >>

Comments

No. I'm waiting for this feature in the common API. Hint: screen.impl_stageDelegate as com.sun.javafx.stage.FrameStageDelegate; delegate.window.setAlwaysOnTop(true); It requires some additional work because of non-public.

Have you tried JFXStage from JFXtras? it has an alwaysOnTop property.

Works great on MacOSX with the Apple Port of Java5... seems that Apple did some compatibility work with the elder JVM.

nice job.....

@ilazarte: Try Java 6u10 or later because the SideBar uses transparent window.

@prunge: I'll try to fix it by using the clip variable, but I can't test it because of single monitor.

Looks cool - but there are problems when running with multiple monitors. When it slides off my primary display (what would normally be the hidden state) it actually slides onto the left of my secondary monitor.

Just a word: amazing.

dont see anything... winxp, java 1.5.0_10. i also launched it via chrome... i see the sidebar app in my application taskbar but i can't find it on screen...