Planet JFX
Register
Advertisement

This Example Application should demonstrate how you can build a JavaFX Application in Window with out the standard Frameborder. This type of application style is usefull for smal apps like chatclients.

The Result can look like this:

Fxapp

You can drag the window by clicking in the titlebar and also minimize or close the applicatin.

Undecorated Frames[]

First of all it is very simple to create a JavaFX Frame without the ambient frame from your windows manager. To do so you only need to set the attribute undecorated to 'true'


import javafx.ui.*;
    Frame {
           title: "Hello World JavaFX"
           width: 200
           height: 50
           content: Label {
               text: "Hello World"
           }
           visible: true
           undecorated: true
    }


But if you do so you will not have any possibility to move or close your frame as you have no Window TitleBar.

So the following code example should demonstrate how to add a nice styled TitleBar to an undecorated frame which enables you to move and close this Frame. This example application is subdivided into two parts. The main frame and a TitleBar Class. The code example displays also two icons (close.png and cross.png). You can take any pictures and put them into a package called "images" to make them visible.

The Main Class[]

The Main Class is a simple frame with to input fields. It should represent a simple address form. Notice that we uncomment the titlebar section in this code.

package demoapp;

import javafx.ui.*;
import javafx.ui.canvas.*;
import java.lang.*;
import java.util.*;
import java.io.*;
import java.text.*;

var chatPanelBackgroundDark = new Color(0.28, 0.28, 0.88, 1.0);
var chatPanelBackgroundLight = new Color(0.50, 0.50, 0.90, 1.0);
var chatPanelBackground = LinearGradient {
    x1: 0
    y1: 0
    x2: 0.075
    y2: 1
    stops:
        [
        Stop {
        offset: 0
        color: chatPanelBackgroundDark
    },
    Stop {
        offset: 0.6
        color: chatPanelBackgroundDark
    },
    Stop {
        offset: 1
        color: chatPanelBackgroundLight
    }
    ]
};

var main=Frame {
    var: frame
    
    title: "Demo Application"
    centerOnScreen: true
    width: 300
    //testFrame.height= 116;
    content: Canvas {
        content:
            [
            View {
            //sizeToFitCanvas: true
            content: BorderPanel {
                
                background: chatPanelBackground
                // uncomment this to display the Titlebar
                //  top: Canvas {
                //  the title bar
                //      content: TitleBar{
                //          title: "Demo Application"
                //          parentFrame: frame
                //      }
                //  }
                
                // the form
                center: GroupPanel {
                    var firstNameRow = Row { alignment: BASELINE }
                    var lastNameRow = Row { alignment: BASELINE }
                    var labelsColumn = Column {
                        alignment: TRAILING
                    }
                    var fieldsColumn = Column {
                        alignment: LEADING
                        resizable: true
                    }
                    rows: [firstNameRow, lastNameRow]
                    columns: [labelsColumn, fieldsColumn]
                    content:
                        [SimpleLabel {
                        row: firstNameRow
                        column: labelsColumn
                        text: "First Name:"
                    },
                    TextField {
                        row: firstNameRow
                        column: fieldsColumn
                        
                        columns: 15
                        value:"Jon"
                    },
                    SimpleLabel {
                        row: lastNameRow
                        column: labelsColumn
                        text: "Last Name:"
                    },
                    TextField {
                        row: lastNameRow
                        column: fieldsColumn
                        columns: 15
                        value: "Smith"
                    }]
                    
                } // groupPanel
            }// borderpanel
        }
        ] // content
    }
};
main.visible = true;
main.undecorated=true;

The Main Frame is very simple and displays the two input fields. We play a little bit with background colors as in a JavaFx application this is normal ;-)

If you start this example you will see a nice application window with out any decoration. So you can not move or close this window from a window header:

Fxapp nobar

Lets talk about the TitleBar element. You can see this additional element if you uncomment the lines in the "top" section of the BorderPanel. This TitleBar allows us now to move the frame and also minimize and close the hole application. If you did not see the icons to close and minimize the window make sure that you have a package named "images" and put in two icons "cross.png" and "icon.png".

TitleBar[]

The TitleBar is a subclass form CompositeNode. The content of this node includes some code to paint a header with the WindowTitle and adds two icons to the right border of the TitleBar. Also in the TitleBar we play a little bit with colors. You can change the style if you like. The Icons to close and minimize the window are constructed using a ImageView. Every Image has a "onMousePressed" event. So this is a very simple functionality. Make sure that you put the images into a package named "images".

The other important functionality of the TitleBar Node is to move the whole window. In the onMousePressed and onMouseDraged Events the TitleBar computes the new position of the main frame and reposition it every time the TitleBar is moved. For that the TitleBar need access to the main frame. And that is the reason why we add a attribute called parentFrame. This is the reference to our ambient main frame.

package demoapp;

import javafx.ui.*;
import javafx.ui.canvas.*;
import javafx.ui.filter.*;
import java.lang.*;


public class TitleBar extends CompositeNode {
    public attribute title: String;
    public attribute parentFrame: Frame;
    
}

function TitleBar.composeNode() = Group {
    selectable: true
    isSelectionRoot: true
    var startx = 0
    var starty = 0
    var headerFont =new Font {faceName: 'Verdana', style: BOLD,  size: 14.0}
    // Mouse pressed
    onMousePressed: operation(e:CanvasMouseEvent)  {
        startx = e.x;
        starty = e.y;
        cursor= MOVE;
        if (e.clickCount >= 2) {
            parentFrame.iconified = true;
        }
    }
    
    // Drag Window
    onMouseDragged: operation(e:CanvasMouseEvent) {
        parentFrame.move(e.x-startx, e.y-starty);
    }
    
    onMouseReleased: operation(e:CanvasMouseEvent) {
        // parentFrame.requestFocus();
    }
    
    var label = SimpleLabel {
        font: headerFont
        text: title
        x: 15
        foreground: new Color(0.82, 0.82, 0.82, 1.0)
    }
    
    content: [
    Rect {
        selectable: true
        width: bind parentFrame.width
        height: 20
        strokeWidth: 2
        stroke: new Color(0.12, 0.12, 0.12, 1.0)
        height: bind label.height
        fill: rgba(0xD9, 0x00, 0x00, 0xff)
        filter: [ ShapeBurst {factor: 4},
        LightFilter {
            highlight: 3
            viewDistance: 300
            diffuseColor: black
            bumpSoftness: 6
            light: AmbientLight {intensity: .5}
        }
        ]
    },
    View {
        content: label
    },
    ImageView {
        transform: [Translate {x:parentFrame.width-20}]
        image: {url: "images/cross.png"}
        onMousePressed: operation(e:CanvasMouseEvent) {
            // close was pressed
            parentFrame.close();
        }
    },
    ImageView {
        transform: [Translate {x:parentFrame.width-40 }]
        image: {url: "images/icon.png"}
        onMousePressed: operation(e:CanvasMouseEvent) {
            // close was pressed
            parentFrame.iconified=true;
            
        }
    }
    
    ] // content
    
};

You can try it out by playing around with this behavior by changing some of the methods.

Concluding Remark[]

Windows without decorating borders look very cool. But consider that if you resign of the window border generated form the underlying operating system you may lose some additional functionality. In modern 3D Desktops like Linux compiz the window manager allows you to do much more than only move or close an application window. You can drag your window to another desktop (or side of your 3D cube) or do some special graphic effects when moving or changing the state of your application window. So you should decide if you want the user to do this things or maybe reduce functionality and control the application window by yourself and create cool styles.

Advertisement