JavaFX

 
→ HOME
→JavaFX
 
 
 
 

 JavaFX Examples

Revised date: 2009/02/11

Pub date: 2008/12/28

Author: Terra

 

Contents

1.Web Applications

  1.1  Communication with Servlet

  1.2  Remote Monitor Servlet

2.Clocks

  2.1  Alarm Clock

3.Games

  3.1  Air Hockey

 

 

 

1.Web Applications

 

1.1  Communication with Servlet

 

This simple JavaFX client communicates with a Servlet.

The client send a name string entered in a SwingTextField to the Servlet by invoking a HTTP Request GET method. When a response is gotten from the Servlet, it is displayed as a Text.

 

・JavaFX Ver.: JavaFX 1.0

 

 

・JavaFX Client Source Code

 

/*

 * HelloClient.fx

 *

 * Created on 2009/02/08, 17:46:43

 */

 

package myclient;

 

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.lang.StringBuffer;

import javafx.ext.swing.SwingButton;

import javafx.ext.swing.SwingTextField;

import javafx.io.http.HttpRequest;

//import javafx.scene.control.TextBox

import javafx.scene.Scene;

import javafx.scene.text.Font;

import javafx.scene.text.Text;

import javafx.stage.Stage;

 

/**

 * @author terra

 */

 

var name: String;

def request: HttpRequest = HttpRequest {

  method: HttpRequest.GET

  onInput: function(input: java.io.InputStream) {

    var buff: StringBuffer = new StringBuffer();

    var reader: BufferedReader

        = new BufferedReader(new InputStreamReader(input));

    var data: String;

    while ((data = reader.readLine()) != null) {

      buff.append(data);

    }

    response = buff.toString();

    reader.close();

  }

}

var response: String;

 

Stage {

  title: "Communication with Servlet"

  width: 350, height: 150

  scene: Scene {

    content: [

      Text {

        x: 10, y: 30

        font: Font{size: 18}

        content: "Enter your name:"

      },

        SwingTextField {

//        TextBox {

        translateX: 155, translateY: 10

        width: 100

        text: bind name with inverse

      },

      SwingButton {

        translateX: 270, translateY: 10

        text: "OK"

        action: function() {

          request.location

              = "http://localhost:8080/HelloServlet/HelloServlet?name={name}";

          request.enqueue();

        }

      }

      Text {

        x: 10, y: 70

        font: Font{size: 24}

        content: bind response

      }

    ]

  }

}

 

 

・Servlet Source Code

 

package myservlet;

 

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

/**

 *

 * @author terra

 */

public class HelloServlet extends HttpServlet {

   

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();

        try {

          out.println("Hello, " + request.getParameter("name") + "!");

        } finally {

            out.close();

        }

    }

 

    @Override

    protected void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

 

    @Override

    protected void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

 

    @Override

    public String getServletInfo() {

        return "Short description";

    }

}

 

 

 

 

1.2  Remote Monitor Servlet

 

This example showcases how to access Servlet cyclically from a JavaFX client.

The client simulates the remote monitor.

 

・JavaFX Ver.: JavaFX 1.0

 

 

・JavaFX Client Source Code

 

/*

 * MonitorClient.fx

 *

 * Created on 2009/02/11, 21:06:43

 */

 

package myclient;

 

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.lang.StringBuffer;

import javafx.animation.KeyFrame;

import javafx.animation.Timeline;

import javafx.ext.swing.SwingButton;

import javafx.ext.swing.SwingTextField;

import javafx.io.http.HttpRequest;

import javafx.scene.paint.Color;

import javafx.scene.paint.LinearGradient;

import javafx.scene.paint.Stop;

import javafx.scene.Scene;

import javafx.scene.shape.Rectangle;

import javafx.scene.text.Font;

import javafx.scene.text.Text;

import javafx.scene.text.TextAlignment;

import javafx.stage.Stage;

 

/**

 * @author terra

 */

 

var response: String = "0";

 

Timeline {

  repeatCount: Timeline.INDEFINITE

  keyFrames: KeyFrame {

    time: 1s

    action: function(): Void {

      request.enqueue();

    }

  }

}.play();

 

def request: HttpRequest = HttpRequest {

  location: "http://localhost:8080/MonitorServlet/MonitorServlet";

  method: HttpRequest.GET

  onInput: function(input: java.io.InputStream) {

    var buff: StringBuffer = new StringBuffer();

    var reader: BufferedReader

        = new BufferedReader(new InputStreamReader(input));

    var data: String;

    while ((data = reader.readLine()) != null) {

      buff.append(data);

    }

    response = buff.toString();

    reader.close();

  }

}

 

Stage {

  title: "Remote Monitor"

  width: 180, height: 150

  scene: Scene {

    content: [

      Rectangle {

        x: 20, y: 20

        width: 40, height: 59

        fill: LinearGradient {

          startX: 0.0, startY: 0.0,

          endX: 1.0, endY: 0.0

          proportional: true

          stops: [

            Stop {offset: 0.0, color: Color.DARKGREEN},

            Stop {offset: 0.3, color: Color.LIMEGREEN},

            Stop {offset: 1.0, color: Color.DARKGREEN}

          ]

        }

      },

      Rectangle {

        x: 20, y: 20

        width: 40

        height: bind 59 - java.lang.Integer.parseInt(response)

        fill: Color.BLACK

      },

      Text {

        x: 35, y: 100

        font: Font{name: "Monospaced", size: 14}

        content: bind "{%2d java.lang.Integer.parseInt(response)}"

      }

    ]

  }

}

 

 

・Servlet Source Code

 

package myservlet;

 

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Calendar;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

/**

 *

 * @author terra

 */

public class MonitorServlet extends HttpServlet {

   

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");

        PrintWriter out = response.getWriter();

        try {

            Calendar rightNow = Calendar.getInstance();

            out.println(String.valueOf(rightNow.get(Calendar.SECOND)));

        } finally {

            out.close();

        }

    }

 

    @Override

    protected void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

 

    @Override

    protected void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

        processRequest(request, response);

    }

 

    @Override

    public String getServletInfo() {

        return "Short description";

    }

}

 

 

 

 

2.Clocks

 

2.1  Alarm Clock

 

This example showcases the following.

  - How to extend the javafx.ext.swing.SwingComponent.

  - How to play a sound.

  - How to show a message dialogue.

 

・JavaFX Ver.: JavaFX 1.0

 

 

・Source Code

 

/*

 * AlarmClock.fx

 * Alarm Clock.

 *

 * Created on 2009/01/11, 14:16:15

 */

 

package clock;

 

import java.applet.Applet;

import java.applet.AudioClip;

import java.awt.Dimension;

import java.lang.Math;

import java.net.URL;

import java.util.Date;

import javafx.animation.KeyFrame;

import javafx.animation.Timeline;

import javafx.ext.swing.SwingButton;

import javafx.ext.swing.SwingComponent;

import javafx.ext.swing.SwingLabel;

import javafx.scene.Group;

import javafx.scene.layout.HBox;

import javafx.scene.layout.VBox;

import javafx.scene.paint.Color;

import javafx.scene.Scene;

import javafx.scene.shape.Circle;

import javafx.scene.shape.Line;

import javafx.scene.text.Font;

import javafx.scene.text.Text;

import javafx.scene.transform.Rotate;

import javafx.scene.transform.Translate;

import javafx.stage.Stage;

import javax.swing.event.ChangeEvent;

import javax.swing.event.ChangeListener;

import javax.swing.JComponent;

import javax.swing.JOptionPane;

import javax.swing.JSpinner;

import javax.swing.SpinnerNumberModel;

 

/**

 * @author terra

 */

 

var url: URL = new URL("{__DIR__}audio/TestMusic.wav");

var audioClip: AudioClip = Applet.newAudioClip(url);

 

var seconds: Integer = 0;

var minutes: Integer = 0;

var hours: Integer = 0;

var timerValue: Number = 0;

var startTime: Number;

var remainingTime: Number;

var alarmEnabled: Boolean = false;

var running: Boolean = false on replace {

  if ((alarmEnabled == true) and (remainingTime <= 0)) {

    alarmEnabled = false;

    audioClip.loop();

    JOptionPane.showMessageDialog(null, "It's time!", "Alarm",

        JOptionPane.WARNING_MESSAGE);

    audioClip.stop();

  }

}

 

var timeline: Timeline = Timeline {

  repeatCount: Timeline.INDEFINITE

  keyFrames: KeyFrame {

    time: 1s

    action: function(): Void {

      var now = new Date();

      remainingTime = timerValue - now.getTime() / 1000 + startTime;

      seconds = remainingTime mod 60 as Integer;

      minutes = (remainingTime / 60) mod 60 as Integer;

      hours = (remainingTime / 60) / 60 as Integer;

      if (remainingTime <= 0) {

        timeline.stop();

        running = false;

        hours = 0;

        minutes = 0;

        seconds = 0;

      } else {

        running = true;

      }

    }

  }

}

 

Stage {

  title: "Alarm Clock"

  scene: Scene {

    width: 310, height: 125

    content: [

      HBox {

        spacing: 20

        content: [

          Group {

            content: [

              Circle {

                centerX: 60, centerY: 60

                radius: 50

                fill: Color.WHITE,

                stroke: Color.BLACK

              },

              Group {

                translateX: 58, translateY: 64

                content:

                for (i in [1..12]) Text {

                  var radians = Math.toRadians(30 * i - 90)

                  transforms: Translate {

                    x: 40 * Math.cos(radians)

                    y: 40 * Math.sin(radians)

                  }

                  content: "{i}"

                  font: Font {

                    size: 10

                  }

                }

              },

              Group {

                translateX: 60, translateY: 60

                content: [

                  Line {    // hours hand

                    endX: 0, endY: -20

                    strokeWidth: 5

                    stroke: Color.BLACK

                    transforms: Rotate {

                      angle: bind hours * 30 + minutes / 2

                    }

                  },

                  Line {    // minutes hand

                    endX: 0, endY: -25

                    strokeWidth: 2

                    stroke: Color.BLUE

                    transforms: Rotate {

                      angle: bind minutes * 6 + seconds / 10

                    }

                  },

                  Line {    // seconds hand

                    endX: 0, endY: -30

                    strokeWidth: 1

                    stroke: Color.RED

                    transforms: Rotate {

                      angle: bind seconds * 6

                    }

                  }

                ]

              },

              Circle {

                centerX: 60, centerY: 60

                radius: 3

              }

            ]

          },

          VBox {

            translateY: 10

            spacing: 10

            content: [

              Group {

                content: [

                  IntSpinner {

                    minimum: 0

                    maximum: 11

                    value: bind hours with inverse

                    translateX: 10

                  },

                  SwingLabel{

                    text: "hour"

                    translateX: 70, translateY: 5

                  }

                ]

              },

              Group {

                content: [

                  IntSpinner {

                    minimum: 0

                    maximum: 59

                    value: bind minutes with inverse

                    translateX: 10

                  },

                  SwingLabel{

                    text: "min "

                    translateX: 70, translateY: 5

                  }

                ]

              },

              Group {

                content: [

                  IntSpinner {

                    minimum: 0

                    maximum: 59

                    value: bind seconds with inverse

                    translateX: 10

                  },

                  SwingLabel{

                    text: "sec "

                    translateX: 70, translateY: 5

                  }

                ]

              }

            ]

          },

          VBox {

            translateX: 10, translateY: 20

            spacing: 30

            content: [

              SwingButton {

                enabled: bind not(running)

                text: "Start"

                action: function(): Void {

                  var date = new Date();

                  timerValue = hours * 3600 + minutes * 60

                      + seconds;

                  startTime = date.getTime() / 1000;

                  remainingTime = timerValue;

                  if (timerValue != 0) {

                    alarmEnabled = true;

                    running = true;

                    timeline.play();

                  }

                }

              },

              SwingButton {

                enabled: bind running

                text: "Stop"

                action: function(): Void {

                  running = false;

                  timeline.stop();

                }

              }

            ]

          }

        ]

      }

    ]

  }

}

 

class IntSpinner extends SwingComponent {

  var spinner: JSpinner;

  var model: SpinnerNumberModel;

  public var minimum: Integer = 0 on replace {

    model.setMinimum(minimum);

  };

  public var maximum: Integer = 10 on replace {

    model.setMaximum(maximum);

  };

  public var value: Integer = 3 on replace {

    spinner.setValue(value);

  };

  public var stepSize: Integer = 1 on replace {

    model.setStepSize(stepSize);

  };

  public override var width = 50;

  public override var height = 25;

  public override function createJComponent(): JComponent {

    model = new SpinnerNumberModel();

    spinner = new JSpinner(model);

    spinner.setPreferredSize(new Dimension(width, height));

    spinner.addChangeListener(ChangeListener {

      public override function stateChanged(e: ChangeEvent) {

        value = spinner.getValue() as Integer;

      }

    });

    return spinner;

  }

}

 

 

 

 

3.Games

 

3.1  Air Hockey

 

・JavaFX Ver.: JavaFX 1.0

 

 

 

・How to play

When you run the program, an air hockey game table with two aqua color mallets are displayed on your screen. Computer's goal (the upper one) and your goal (the lower one) are displayed in burlywood color.

Push the "SET" button to start the game. Then, a white puck appears on your side.

You can manipulate your mallet by the mouse as long as it resides in your area.

A velocity of your mallet is computed from its displacement by applying the scaling transformation. The scaling is modulated by the velocityScaling factor. You can make your mallet's velocity more real by moving the factor closer to 1.0.

You can also regulate the bounce back speed by adjusting the elastic modulus elastic.

In this program, a computer simply move its mallet back and forth. It has no ability to take the offensive.

 

・Source Code

 

/*

 * AirHockey.fx

 * The air hockey game.

 *

 * Created and modified:

 * V 1.0.0    2008/09/25 Created.

 * V 2.0.0    2008/12/28 Modified to conform to JavaFX 1.0.

 */

 

package game;

 

import java.lang.Math;

import javafx.animation.*;

import javafx.scene.*;

import javafx.scene.effect.*;

import javafx.scene.effect.light.*;

import javafx.scene.input.MouseEvent;

import javafx.scene.paint.*;

import javafx.scene.shape.Circle;

import javafx.scene.shape.Line;

import javafx.scene.shape.Rectangle;

import javafx.scene.text.*;

import javafx.stage.Stage;

 

/**

 * @author terra

 */

 

var goalCorners: Disc[];

var mouseEvent: MouseEvent;

 

var tableWidth: Number = 300;

var tableHeight: Number = 400;

var goalWidth: Number = 80;

var goalCornerRadius: Number = 5;

var puckRadius: Number = 10;

var malletRadius: Number = 15;

var hittingAreaDepth: Number = tableHeight / 2 - malletRadius;

var elastic: Number = 0.95;

var velocityScaling = 0.35;

var malletCMaxV = 2;    // Maximum velocity of the computer's mallet.

 

var timingGenerator: Timeline = Timeline {

  repeatCount: Timeline.INDEFINITE

  keyFrames: KeyFrame {

    time: 20ms

    action: function(): Void {

      malletC.move();

      puck.move();

      malletH.calcuVelocity();

      puck.collide(malletH);

      puck.collide(malletC);

      for (corner in goalCorners) {

        puck.collide(corner);

      }

      score.judgeGoal();

    }

  }

};

 

var puck: Puck = Puck {

  x: -(puckRadius + 1)

  y: goalCornerRadius + tableHeight / 2

  radius: puckRadius

  vX: 0, vY: 0

}

 

var malletH: MalletH = MalletH {    // Human's mallet.

  x: bind mouseEvent.sceneX

  y: bind mouseEvent.sceneY

  radius: malletRadius

  color: Color.AQUA

}

 

var malletC: MalletC = MalletC {    // Computer's mallet.

  x: goalCornerRadius + tableWidth / 2

  y: goalCornerRadius + malletRadius + puckRadius

  radius: malletRadius

  color: Color.AQUA

  vX: malletCMaxV, vY: 0

}

 

for (i in [0..1]) {

  for (j in [0..1]) {

    insert Disc {

      x: (tableWidth - goalWidth) / 2  + j * goalWidth

      y: i * (2 * goalCornerRadius + tableHeight)

      radius: goalCornerRadius

      color: Color.LIGHTGREY

    } into goalCorners;

  }

}

 

var score: Score = Score{}

 

Stage {

  title: "Air Hockey"

  width: 2 * goalCornerRadius + tableWidth + 56 as Integer

  height: 2 * goalCornerRadius + tableHeight + 28 as Integer

  scene: Scene {

    width: 2 * goalCornerRadius + tableWidth as Integer

    height: 2 * goalCornerRadius + tableHeight as Integer

    fill: Color.LIGHTGRAY

    content: [

      Rectangle {    // Jointed goal area.

        x: (tableWidth - goalWidth) / 2, y: 0

        width: goalWidth

        height: 2 * goalCornerRadius + tableHeight + 2

        fill: Color.BURLYWOOD

      },

      Rectangle {    // Table.

        x: goalCornerRadius, y: goalCornerRadius

        width: tableWidth, height: tableHeight

        fill: Color.OLIVE

      },

      Rectangle {    // Human's hittig area.

        x: goalCornerRadius + malletRadius

        y: goalCornerRadius + tableHeight - hittingAreaDepth

        width: tableWidth - 2 * malletRadius

        height: hittingAreaDepth - malletRadius

        fill: Color.OLIVE

        onMouseMoved: function(ev: MouseEvent): Void {

          mouseEvent = ev;

        }

      },

      Line {    // Center line.

        startX: goalCornerRadius

        startY: goalCornerRadius + tableHeight / 2

        endX: goalCornerRadius + tableWidth - 1

        endY: goalCornerRadius + tableHeight / 2

        stroke: Color.BLUE

      },

      puck,

      malletH,

      malletC,

      goalCorners,

      ScoreIndicator {

        x: 2 * goalCornerRadius + tableWidth + 5 as Integer

        y: goalCornerRadius + tableHeight / 2 - 24 as Integer

        score: bind score.scoreC

      },

      ScoreIndicator {

        x: 2 * goalCornerRadius + tableWidth + 5 as Integer

        y: goalCornerRadius + tableHeight / 2 + 5 as Integer

        score: bind score.scoreH

      },

      Rectangle {    // "SET" button.

        x: 2 * goalCornerRadius + tableWidth + 5 as Integer

        y: goalCornerRadius + tableHeight - 30 as Integer

        width: 35,

        height: 30

        arcWidth: 8,

        arcHeight: 8

        fill: Color.DARKGREY

        effect: Lighting {

          light: DistantLight {

            azimuth: 225,

            elevation: 50

          }

        }

        onMousePressed: function(ev: MouseEvent): Void {

          puck.x = goalCornerRadius + tableWidth / 2;

          puck.y = goalCornerRadius + 2 * tableHeight / 3;

          puck.vX = 0;

          puck.vY = 0;

          timingGenerator.play();

        }

      },

      Text {

        x: 2 * goalCornerRadius + tableWidth + 10 as Integer

        y: goalCornerRadius + tableHeight - 20 as Integer

        textOrigin: TextOrigin.TOP

        fill: Color.YELLOW

        font: Font {

          size: 14

          name: "Monospaced",

          embolden: true

        }

        effect: DropShadow {

          offsetX: 3, offsetY: 3

          radius: 2

          color: Color.BLACK

        }

        content: "SET"

      }

    ]

  }

}

 

class Disc extends CustomNode {

  var x: Number;

  var y: Number;

  var radius: Number;

  var color: Color = Color.WHITE;

  var vX: Number;

  var vY: Number;

  var lastX: Number = x;

  var lastY: Number = y;

 

  override function create(): Node {

    return Circle {

      centerX: bind x,

      centerY: bind y

      radius: bind radius

      fill: bind color

    };

  }

}

 

class Puck extends Disc {

  function move(): Void {

    x += vX;

    y += vY;

 

    if (x + radius > goalCornerRadius + tableWidth) {

      x = goalCornerRadius + tableWidth - radius;

      vX *= -1.0 * elastic;

    } else if (x - radius < goalCornerRadius) {

      x = goalCornerRadius + radius;

      vX *= -1.0 * elastic;

    }

 

    if (x >= 0) {

      if (y > 2 * goalCornerRadius + tableHeight) {

        // It crossed the Human's goal line.

        x = -(radius + 1);

        y = 2 * goalCornerRadius + tableHeight + radius;

        vX = 0;

        vY = 0;

      } else if (y + radius > tableHeight + goalCornerRadius) {

        if ((x < (tableWidth - goalWidth) / 2)

            or (x > (tableWidth + goalWidth) / 2)) {

          y = tableHeight + goalCornerRadius - radius;

          vY *= -1.0 * elastic;

        }

      } else if (y < 0) {

        // It crossed the computer's goal line.

        x = -(radius + 1);

        y = -radius;

        vX = 0;

        vY = 0;

      } else if (y - radius < goalCornerRadius) {

        if ((x < (tableWidth - goalWidth) / 2)

            or (x > (tableWidth + goalWidth) / 2)) {

          y = goalCornerRadius + radius;

          vY *= -1.0 * elastic;

        }

      }

    }

  }

 

  function collide(disc: Disc): Void {

    var distX: Number = disc.x - x;

    var distY: Number = disc.y - y;

    var minDist: Number = disc.radius + radius;

    var dist2: Number = distX * distX + distY * distY;

    var minDist2: Number = minDist * minDist;

 

    if (dist2 < minDist2) {

      var colAngle: Number = Math.atan2(distY, distX);

      var sinColAngle: Number = Math.sin(colAngle);

      var cosColAngle: Number = Math.cos(colAngle);

 

      var expres1: Number = disc.vX * cosColAngle

          + disc.vY * sinColAngle;

      var expres2: Number = vX * sinColAngle - vY * cosColAngle;

      var expres3: Number = vX * cosColAngle + vY * sinColAngle;

 

      x = disc.x - minDist * cosColAngle;

      y = disc.y - minDist * sinColAngle;

 

      vX = (1 + elastic) * expres1 * cosColAngle

          + expres2 * sinColAngle - elastic * expres3 * cosColAngle;

      vY = (1 + elastic) * expres1 * sinColAngle

          - expres2 * cosColAngle - elastic * expres3 * sinColAngle;

    }

  }

}

 

class MalletH extends Disc {

  function calcuVelocity(): Void {

    vX = velocityScaling * (x - lastX);

    vY = velocityScaling * (y - lastY);

    lastX = x;

    lastY = y;

  }

}

 

class MalletC extends Disc {

  function move(): Void {

    x += vX;

 

    if (x + radius > 2 * goalCornerRadius + tableWidth / 2

        + goalWidth / 2) {

      x = 2 * goalCornerRadius + tableWidth / 2

           + goalWidth / 2- radius;

      vX *= -1.0;

    } else if (x - radius < tableWidth / 2 - goalWidth / 2) {

      x = tableWidth / 2 - goalWidth / 2 + radius;

      vX *= -1.0;

    }

  }

}

 

class Score {

  var scoreC: Integer = 0;    // Computer's score.

  var scoreH: Integer = 0;    // Human's score.

 

  function judgeGoal(): Void {

    if (puck.x < 0) {

      if (puck.y > 2 * goalCornerRadius + tableHeight) {

        scoreC += 1;

      } else if (puck.y < 0) {

        scoreH += 1;

      }

      puck.y = goalCornerRadius + tableHeight / 2;

      timingGenerator.stop();

    }

  }

}

 

class ScoreIndicator extends CustomNode {

  var score: Integer = 0;

  var x: Integer = 0;

  var y: Integer = 0;

  var width: Integer = 21;

  var height: Integer = 18;

  var fillColor: Color = Color.WHITE;

  var borderColor: Color = Color.YELLOWGREEN;

  var scoreTextColor: Color = Color.BLACK;

 

  override function create(): Node {

    Group {

      content: [

        Rectangle {

          x: x, y: y

          width: width, height: height

          arcWidth: 6, arcHeight: 6

          stroke: borderColor,

          fill: fillColor

        },

        Text {

          x: x + 4 * height / 18 as Integer

          y: y + 5 * height / 18 as Integer

          textOrigin: TextOrigin.TOP

          fill: scoreTextColor

          font: Font {

            size: 14 * height / 18 as Integer

            name: "Monospaced",

            embolden: true

          }

          content: bind "{%2d score}"

        }

      ]

    }

  }

}

 

Yahoo!ジオシティーズ