28 outubro 2008

First JavaFX experiment

I constructed my first JavaFX example to became to answer some of my questions posted here and to "feel" this script language. I will explain it above:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package brunogrossi.javafx;

import javafx.application.*;
import javafx.input.*;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.geometry.*;
import javafx.scene.text.*;
import javafx.scene.effect.*;
import javafx.scene.effect.light.*;
import javafx.ext.swing.*;
import javafx.animation.*;

var slider = Slider{minimum: 0 maximum: 360 value: 20};
var canvas:Node = ComponentView{component:Canvas {
content: Group {
content: [
ComponentView {
component: slider
translateX: 10
translateY: 70
},
Rectangle {
x: 10 y: 10
width: 200 height: 50
arcWidth: 15 arcHeight: 15
fill: Color.LIGHTGRAY
},
Text {
x: 110 y: 40
content: "JavaFX"
font: Font {
name: "Serif"
size: 20
style: FontStyle.BOLD
}
fill: Color.YELLOW
horizontalAlignment: HorizontalAlignment.CENTER
effect: DropShadow {
offsetX: 2 offsetY: -2 radius: 6
color: Color.BLACK
}
}
]
effect: Lighting {
light: DistantLight {
azimuth: bind slider.value
}
}
}

}};

public class TitleBar extends CustomNode {

private attribute frame: Frame;
private attribute width: Number = 10;
private attribute dragStartPoint: java.awt.geom.Point2D;
attribute bgcolor: Color = Color.BLUE;
attribute fgcolor: Color = Color.WHITE;

private attribute iRotate = 0;
private attribute iRotating = false;

public function create():Node {
this.onMousePressed = function(e:MouseEvent):Void {
this.dragStartPoint = e.getLocalXY();
}
this.onMouseReleased = function(e:MouseEvent):Void {
this.dragStartPoint = null;
}
this.onMouseDragged = function(e:MouseEvent):Void {
this.frame.x = (e.getScreenX() - this.dragStartPoint.getX() as Integer);
this.frame.y = (e.getScreenY() - this.dragStartPoint.getY() as Integer);
}

return Group {
content: [
Rectangle{
x: 0
y: 0
width: bind width
height: bind frame.height

fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
proportional: true
stops: [
Stop { offset: 0.0 color: Color.WHITE },
Stop { offset: 1.0 color: bind bgcolor }
]
}
},

javafx.scene.geometry.Polygon {
var t = Timeline {
autoReverse: false

keyFrames: [KeyFrame{time : 0s
values: iRotate => 0.0},

KeyFrame{time : 2s
values: iRotate => 180.0 tween Interpolator.LINEAR
action: function() {this.iRotating = false}
}
]//keyFrames
}//Timeline;
transform: javafx.scene.transform.Rotate{
angle: bind iRotate
x: 2+(width-2-2)/2
y: 2+(width-2-2)/2
};
stroke: Color.BLACK
fill: Color.BLANCHEDALMOND
points: [
2, 2,
2, width-2,
width-2, width-2,
width-2, 2,
2, width-2,
2, 2,
width-2, width-2,
width-2, 2
]
onMouseClicked: function(e: MouseEvent):Void {
//Interessant point to be analized: how to call function on variables.
if (frame.closeAction!=null)
frame.closeAction();
}
onMouseEntered: function(e: MouseEvent):Void {
if (not this.iRotating) {
this.iRotating = true;
t.start();
}
}
},
Text {
content: bind frame.title
fill: bind fgcolor

textOrigin: TextOrigin.BASELINE
rotate: -90
x: 0
y: 0
translateX: bind width
translateY: bind frame.height
}
]
}
}
}

public class MyFrame extends Frame {

postinit {
insert TitleBar{
frame: this
bgcolor:Color.BLACK
} before this.stage.content[0];
}

function createWindow(): java.awt.Window {
//this is a trick, because Frame don't has a undecorated attribute.
var f: java.awt.Window = super.createWindow();
(f as javax.swing.JFrame).setUndecorated(true);
return f;
}

}

var f:Frame = MyFrame {
title: "Example"
width: 228
height: 140
opacity: 0.5
closeAction: function() {
java.lang.System.exit(1);
}
stage: Stage {
content: [canvas]
}

}

f.visible=true;

My goal with this test was to create a custom title bar to my Frame. And a lateral (rotated) title bar! So, the slider and canvas variables are part of the body of my frame, and was adapted from this tutorial, and are doesn't explained here. The content of MyFrame must be anything...

First, I created a CustomNode called TitleBar (lines 54-144). The javafx.scene.CustomNode defines a Node that can be customized, only defining the create():Node function.

This TitleBar class has an attribute frame, that will be the frame that this component will control. The TitleBar will be associated with the frame on MyFrame's postinit instruction (lines 146-153). The magic is to insert a new TitleBar object as a first element on this frame's Stage content. Here, we define the frame as this frame, and the background's color. Only this..

In MyFrame's definition there is other function defined: createWindow(). I just defined it to set the window as a Undecorated window. This is a trick. As I report on JavaFX forum, the old javafx.ui.frame has an attribute to define it as a undecorated frame, but the new javafx.application.Frame and javafx.ext.swing.SwingFrame hasn't. That's how I do to turn the frame undecorated.

The TitleBar class has a reference to the Frame that it will command and an MouseListener that change frame's position based on Drag events. The Text value binds to Frame's title and close button's event simply calls the Frame's closeAction() function. So, we don't need to configure the title bar, because it uses "frame's configurations".

By the away, in the close button, I created an effect to test simple animation. When the cursor is over square, it will rotate. For my surprise, the construction that I used on previews version, var i=[0..360] dur 1000 don't work now. I need to use a javafx.animation.Timeline (lines 99-110). Timeline is a good class, but for simple animations, the other construction is better and simple... Is there another construction like that?

That's the window:

3 comentários:

Anônimo disse...

Hi,
one Correction: You don't need createWindow() to set javafx.application.Frame Undecorated or even Transparent.
Use:
var f:Frame = MyFrame {
windowStyle: WindowStyle.TRANSPARENT//UNDECORATED

...

}

Regards, David Riepenhausen (Riepi)

Bruno E. Grossi disse...
Este comentário foi removido pelo autor.
Bruno E. Grossi disse...

Yes, David.. now I known that. A lot of things was changed in JavaFX...

Thanks,
Bruno