How can I align a DataTip to the vertical center of the corresponding column? I've tried creating a custom dataTipRenderer, but it seems to me that there I can only move the datatip relative to the target (the circle graphic). But that position's just fine, I'd like to move the target itself.
My last idea is to set the showDataTipTargets style of the chart to false and draw the targets within the custom dataTipRenderer. I consider this a dirty hack, so if there's anything more friendly I'd go with that. Plus, in this case, how can I tell the column center coordinates in the datatip renderer's updateDisplayList function?
Hope this snippet of code would help ...
package As
{
import flash.display.*;
import flash.geom.Point;
import mx.charts.*;
import mx.charts.chartClasses.DataTip;
import mx.charts.series.ColumnSeries;
import mx.charts.series.items.ColumnSeriesItem;
public class MyDataTip extends DataTip
{
private var _xBaseLine:int=0;
private var _yBaseLine:int=0;
private var myX = 0
private var myY = 0
public function MyDataTip()
{
super();
}
override public function set data(arg1:Object):void {
var sMessage:String;
var pt:Point;
var hitData:HitData = mx.charts.HitData(arg1);
var chartItem = ColumnSeriesItem(hitData.chartItem);
var renderer = chartItem.itemRenderer;
var series = ColumnSeries(hitData.element);
var colName = chartItem.element.name
var pft = chartItem.xValue
if(renderer != null) {
myX = ( renderer.width / 2 )
myY = ( renderer.height/ 2 ) + ( this.height)
}
super.data=arg1;
}
override public function move (x:Number, y:Number):void {
// Adjusted
var pointAdjusted:Point = new Point(x + _xBaseLine, y + _yBaseLine);
// Call the parent
super.move(pointAdjusted.x, pointAdjusted.y);
}
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
this.x = this.x + myX - 15
this.y = this.y + myY - 7
}
}
}
Cheers !! :)
Related
I've been trying out Tornadofx. trying to create a custom title-bar, here's the code I'm currently trying
fun main(args: Array<String>) {
launch<MyApp>(args)
}
class MyApp : App(Title::class) {
override fun start(stage: Stage) {
stage.initStyle(StageStyle.UNDECORATED)
stage.minWidth = 600.0
stage.minHeight = 450.0
stage.isMaximized = false
super.start(stage)
}
}
class Title : View() {
private var xOffset = 0.0
private var yOffset = 0.0
private var screenBounds: Rectangle2D = Screen.getPrimary().visualBounds
private var originalBounds: Rectangle2D = Rectangle2D.EMPTY
init {
primaryStage.isMaximized = false
}
override val root = borderpane {
onMousePressed = EventHandler { ev ->
xOffset = primaryStage.x - ev.screenX
yOffset = primaryStage.y - ev.screenY
}
onMouseDragged = EventHandler { ev ->
primaryStage.x = xOffset + ev.screenX
primaryStage.y = yOffset + ev.screenY
}
center = label("Forms")
right = hbox {
button("Mi") {
action {
with(primaryStage) { isIconified = true }
}
}
button("Ma") {
action {
if (primaryStage.isMaximized) {
with(primaryStage) {
x = originalBounds.minX
y = originalBounds.minY
width = originalBounds.width
height = originalBounds.height
isMaximized = false
}
text = "Ma"
} else {
with(primaryStage) {
originalBounds = Rectangle2D(x, y, width, height)
x = screenBounds.minX
y = screenBounds.minY
width = screenBounds.width
height = screenBounds.height
isMaximized = true
}
text = "Re"
}
}
}
button("X") {
action {
app.stop()
println("exiting")
exitProcess(0)
}
}
}
}
}
the following work without problems
close
maximize, restore
restored window minimized, then open from taskbar
but when a maximized window is minimized to taskbar, then open from taskbar, it goes full screen(taskbar is hidden)
how do i fix this behavior, is there any part of my code that is wrong, needs change, or in need of any inclusions?
my configuration is Windows 10 64bit, Java 11.0.2, Kotlin 1.4.21, JavaFx 11.0.2, TornadoFx 1.7.20
I think this is a general problem in JavaFX (I mean not specific with TornadoFX).
The root cause for this is because of setting the maximized property of stage to true. Not sure what JavaFX internally does, but when you open the window from task bar and if the maximized value is true, then it renders in full screen mode.
You can fix this in two ways.
Approach #1:
When the window is opened from task bar, the iconfied property will turn off, set the stage dimensions again to screen bounds if maximized is true.
primaryStage.iconifiedProperty().addListener((obs,old,iconified)->{
if(!iconified && primaryStage.isMaximized()){
primaryStage.setWidth(screenBounds.getWidth());
primaryStage.setHeight(screenBounds.getHeight());
}
});
Approach #2:
Don't rely on the maximized property of the Stage. I believe you need that property to toggle the window dimensions. So instead maintain a instance variable to handle that.
boolean maximized = false;
ma.setOnAction(e -> {
if (maximized) {
// Set stage to original bounds
maximized = false;
ma.setText("Ma");
} else {
// Set stage to screen bounds
maximized = false;
ma.setText("Re");
}
});
A full working demo is below with both the approaches. You can decide which way to go based on your other requirments.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class UndecoratedWindowFullScreenDemo extends Application {
private double xOffset = 0.0;
private double yOffset = 0.0;
private Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
private Rectangle2D originalBounds = Rectangle2D.EMPTY;
private boolean maximized = false;
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
root.setStyle("-fx-background-color:pink;");
Scene scene = new Scene(root, 600, 450);
primaryStage.setScene(scene);
Label label = new Label("Forums");
Button mi = new Button("Mi");
Button ma = new Button("Ma");
Button x = new Button("X");
HBox pane = new HBox(mi, ma, x);
pane.setPadding(new Insets(3));
pane.setSpacing(5);
root.setCenter(label);
root.setRight(pane);
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setMinWidth(600);
primaryStage.setMinHeight(450);
primaryStage.setMaximized(false);
primaryStage.show();
root.setOnMousePressed(e -> {
xOffset = primaryStage.getX() - e.getScreenX();
yOffset = primaryStage.getY() - e.getScreenY();
});
root.setOnMouseDragged(e -> {
primaryStage.setX(xOffset + e.getScreenX());
primaryStage.setY(yOffset + e.getScreenY());
});
mi.setOnAction(e -> primaryStage.setIconified(true));
/* Use this approach if you want to go with the Stage maximized property */
// approach1(primaryStage, ma);
/* Use this approach if you want to avoid Stage maximized property and maintain a instance variable */
approach2(primaryStage, ma);
}
private void approach1(Stage primaryStage, Button ma) {
primaryStage.iconifiedProperty().addListener((obs, old, iconified) -> {
if (!iconified && primaryStage.isMaximized()) {
primaryStage.setWidth(screenBounds.getWidth());
primaryStage.setHeight(screenBounds.getHeight());
}
});
ma.setOnAction(e -> {
if (primaryStage.isMaximized()) {
primaryStage.setX(originalBounds.getMinX());
primaryStage.setY(originalBounds.getMinY());
primaryStage.setWidth(originalBounds.getWidth());
primaryStage.setHeight(originalBounds.getHeight());
primaryStage.setMaximized(false);
ma.setText("Ma");
} else {
originalBounds = new Rectangle2D(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight());
primaryStage.setX(screenBounds.getMinX());
primaryStage.setY(screenBounds.getMinY());
primaryStage.setWidth(screenBounds.getWidth());
primaryStage.setHeight(screenBounds.getHeight());
primaryStage.setMaximized(true);
ma.setText("Re");
}
});
}
private void approach2(Stage primaryStage, Button ma) {
ma.setOnAction(e -> {
if (maximized) {
primaryStage.setX(originalBounds.getMinX());
primaryStage.setY(originalBounds.getMinY());
primaryStage.setWidth(originalBounds.getWidth());
primaryStage.setHeight(originalBounds.getHeight());
maximized = false;
ma.setText("Ma");
} else {
originalBounds = new Rectangle2D(primaryStage.getX(), primaryStage.getY(), primaryStage.getWidth(), primaryStage.getHeight());
primaryStage.setX(screenBounds.getMinX());
primaryStage.setY(screenBounds.getMinY());
primaryStage.setWidth(screenBounds.getWidth());
primaryStage.setHeight(screenBounds.getHeight());
maximized = true;
ma.setText("Re");
}
});
}
}
There are two changes that were needed to solve the problem
The actual problem was that if isMaximized is set to true the app goes full screen when being open from task(minimized) even though isFullScreen property is separately available
Adding a maximized property listener so that we can invalidate if the isMaximized were to be ever modified by other means(like double clicking on title bar in Linux etc)
// CHANGE 1
stage.maximizedProperty().addListener { _, _, newValue ->
if (newValue) stage.isMaximized = false
}
by having a separate maximized instead of using isMaximized
// CHANGE 2
private var maximized: Boolean = false // <- here
if (maximized) { // <- here
// restore the window by setting bounds of original size
maximized = false // <- here
text = "Ma"
} else {
// maximize window by setting bounds from screen size
maximized = true // <- and here
text = "Re"
}
Bonus : use isFocusTraversable = false to make buttons that don't focus with keyboard traversal
Final solution
fun main(args: Array<String>) {
launch<MyApp>(args)
}
class MyApp : App(Window::class, Styles::class) {
override fun start(stage: Stage) {
stage.initStyle(StageStyle.UNDECORATED)
stage.minWidth = 600.0
stage.minHeight = 450.0
stage.width = 600.0
stage.height = 450.0
// CHANGE 1
stage.maximizedProperty().addListener { _, _, newValue ->
if (newValue) stage.isMaximized = false
}
stage.isMaximized = false
super.start(stage)
}
}
class Window : View() {
override val root = borderpane {
top = Title().root
}
}
class Title : View() {
// CHANGE 2
private var maximized: Boolean = false // <- here
private var xOffset = 0.0
private var yOffset = 0.0
private var screenBounds: Rectangle2D = Screen.getPrimary().visualBounds
private var originalBounds: Rectangle2D = Rectangle2D.EMPTY
init {
primaryStage.isMaximized = false
}
override val root = hbox {
hgrow = Priority.ALWAYS
onMousePressed = EventHandler { ev ->
xOffset = primaryStage.x - ev.screenX
yOffset = primaryStage.y - ev.screenY
}
onMouseDragged = EventHandler { ev ->
primaryStage.x = xOffset + ev.screenX
primaryStage.y = yOffset + ev.screenY
}
val l1 = hbox {
hgrow = Priority.ALWAYS
alignment = Pos.CENTER
label("Forms")
}
add(l1)
l1.requestFocus()
button("Mi") {
id = "min"
action {
with(primaryStage) { isIconified = true }
}
isFocusTraversable = false
}
button("Ma") {
id = "max"
action {
if (maximized) { // <- here
with(primaryStage) {
x = originalBounds.minX
y = originalBounds.minY
width = originalBounds.width
height = originalBounds.height
maximized = false // <- here
}
text = "Ma"
} else {
with(primaryStage) {
originalBounds = Rectangle2D(x, y, width, height)
x = screenBounds.minX
y = screenBounds.minY
width = screenBounds.width
height = screenBounds.height
maximized = true // <- and here
}
text = "Re"
}
l1.requestFocus()
}
isFocusTraversable = false
}
button("X") {
id = "close"
action {
app.stop()
println("exiting")
exitProcess(0)
}
isFocusTraversable = false
}
}
}
I need to set up a simulation of a nuclear power plant in JavaFX. The GUI is working perfectly, but I've got problems with getting the simulation run. I have to use a Timeline (as EventHandler) for this, the handler updates the radiation value in each cell every single tick. The radiation is displayed as a circle on each cell. The higher the radiation, the bigger should the circle be. For this, I made an if-else-statement.
The problem is: The if-statement cannot access the variables from the EventHandler. But this is necessary to update the circle size each tick. I already tried to put the if-statements right into the EventHandler, but then, no circles have been shown anymore on my GUI.
These are the three classes so far:
EDIT: I put the if-statements into the Event Handler, new code below.
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class NuclearPowerPlant extends Application {
private static final int HEIGHT = 50;
private static final int WIDTH = 55;
private static final int CELL_SIZE = 40;
#Override
public void start(Stage stage) {
stage.setScene(new Scene(createContent()));
stage.show();
}
private Parent createContent() {
Pane root = new Pane();
root.setPrefSize((WIDTH - 40) * CELL_SIZE, (HEIGHT - 40) * CELL_SIZE); // Size of displayed window
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
Cell cell = new Cell(x, y);
root.getChildren().add(cell);
}
}
return root;
}
public static void main(String[] args) {
launch(args);
}
}
Cell:
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.util.Duration;
public class Cell extends StackPane {
private static final int CELL_SIZE = 40;
int x;
int y;
private Rectangle cell;
private Circle radiation; // Radiation is displayed as a circle
int circlesize; // Size of the circle (the higher the radiation, the bigger the circle)
double radiationvalue = 5000; // Initializing of the radiation value of all cells at the beginning (air in all cells)
private Text symbol; // For Explosion
double activity;
double reflection;
public Cell(int x, int y) { // Konstruktor fuer die Zelle
setTranslateX(x * CELL_SIZE);
setTranslateY(y * CELL_SIZE);
cell = new Rectangle(CELL_SIZE - 2, CELL_SIZE - 2, Color.BLUE);
cell.setStroke(Color.WHITE);
EventHandler<ActionEvent> handlerUpdateRadiationvalue = event -> {
double newradiationvalue = activity + reflection * 500;
// System.out.println(newradiationvalue);
if (newradiationvalue < 1000) {
this.circlesize = 2;
} else if (newradiationvalue >= 1000 && newradiationvalue < 3000) {
this.circlesize = 5;
} else if (newradiationvalue >= 3000 && newradiationvalue < 5000) {
this.circlesize = 8;
} else if (newradiationvalue >= 5000 && newradiationvalue < 7000) {
this.circlesize = 11;
} else if (newradiationvalue >= 7000 && newradiationvalue < 9000) {
this.circlesize = 14;
} else if (newradiationvalue >= 9000 && newradiationvalue < 10000) {
this.circlesize = 18;
}
// Explosion:
else if (newradiationvalue >= 10000) {
circlesize = 0;
cell.setFill(Color.RED);
symbol = new Text("X");
symbol.setFont(Font.font(38));
}
};
KeyFrame keyframe = new KeyFrame(Duration.seconds(0.02), handlerUpdateRadiationvalue);
Timeline tl = new Timeline();
tl.getKeyFrames().addAll(keyframe);
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
radiation = new Circle(circlesize, Color.BLACK);
getChildren().add(cell);
if (radiationvalue < 10000) {
getChildren().add(radiation);
} else {
getChildren().add(symbol);
}
// Context Menu for material change:
ContextMenu contextMenu = new ContextMenu();
MenuItem air = new MenuItem("Luft");
air.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
activity = Material.AIR.getActivity();
reflection = Material.AIR.getReflection();
cell.setFill(Color.BLUE);
}
});
MenuItem uranium = new MenuItem("Uran");
uranium.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
activity = Material.URANIUM.getActivity();
reflection = Material.URANIUM.getReflection();
cell.setFill(Color.GREEN);
}
});
MenuItem lead = new MenuItem("Blei");
lead.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
activity = Material.LEAD.getActivity();
reflection = Material.LEAD.getReflection();
cell.setFill(Color.GREY);
}
});
MenuItem ruleblock = new MenuItem("Regelblock");
ruleblock.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
activity = Material.RULEBLOCK.getActivity();
reflection = Material.RULEBLOCK.getReflection();
cell.setFill(Color.YELLOW);
}
});
contextMenu.getItems().addAll(air, uranium, lead, ruleblock);
cell.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
#Override
public void handle(ContextMenuEvent event) {
contextMenu.show(cell, event.getScreenX(), event.getScreenY());
}
});
}
ENUM:
public enum Material {
AIR (0, 0.99),
URANIUM (1, 1.12),
LEAD (0, 0.7),
RULEBLOCK (0, 0.99);
double activity;
double reflection;
private Material(double activity, double reflection) {
this.activity = activity;
this.reflection = reflection;
}
double getActivity() {
return activity;
}
public void setActivity(double activity) {
this.activity = activity;
}
double getReflection() {
return reflection;
}
public void setReflection(double reflection) {
this.reflection = reflection;
}
}
The if statement always links to the global variable "radiationvalue" instead of the updated value in the event handler. If I try to access the 'newradiationvalue' in the if statement, I get an error that no such variable can be found (because the one in the Event Handler is not visible from outside).
Maybe someone can tell me how to access the variables in the event handler from outside the event handler?! And if it's not possible: How do I need to change my program to make this work as I want?
Thanks very much in advance!
I'm trying to get realtime rainbow text in a single word and reset to red when I space to the next word to create another rainbow word.
For instance, if I want to type the string, "his forgiveness", I want "h" to be red, "i" to be orange, "s" to be yellow, "f" to be red, "o" to be orange, "r" to be yellow, "g" to be green, "i" to be blue, "v" to be indigo, "e" to be violet. The remaining, "ness" can all be violet, I don't care. I just need the original concept down.
So far, I'm only able to change the color of the whole text area on a keypress(s) and not a single string character.
To fast forward to where I am, follow this quick 4 point process:
(1/4)Paste the following code on the stage.
counter = -1;
var key:Object = {onKeyDown:function () {
counter = counter+1;
if (counter == 1) {
inp.textColor = 0xFF0000;
}
if (counter == 2) {
inp.textColor = 0xFF9900;
}
if (counter == 3) {
inp.textColor = 0xFFFF00;
}
}};
Key.addListener(key);
(2/4)Make an input box with the instance name, "inp"
(3/4)Test the movie.
(4/4)Select the textbox and start typing in it.
I only have it changing the whole text box from your default color to red then orange than yellow. Getting a true rainbow code will be what I've long waited for if you can help.
In order to implement different colors on a single textfield you must use this properties on your textfield:
myTextField.html = true
myTextField.htmlText = 'bli bli bli<font color="#0000FF">bla bla bla/font>'
or you can use the TextFormat class to do so.
Here is how you can do.
tField.text = "bli bli bli";
var tFormat:TextFormat = new TextFormat();
tFormat.color = 0xff0000;
tField.setTextFormat(0,5,tFormat);
tFormat.color = 0x33cc33;
tField.setTextFormat(5,9,tFormat);
and in order to get the colors as you type use this class:
package {
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.events.KeyboardEvent;
import flash.events.Event;
public class ColorTextField extends TextField{
var tf:TextFormat = new TextFormat();
var ar:Array = new Array(0xFF0000,0x00FF00,0x0000FF,0x123456);
public function ColorTextField() {
// constructor code
this.type = TextFieldType.INPUT;
tf.size = 33;
this.defaultTextFormat = tf;
this.addEventListener(KeyboardEvent.KEY_UP,onKeyUp);
}
private function onKeyUp(event:KeyboardEvent):void{
var index:int = 0;
var colorIndex:int = 0;
while (index < this.text.length){
var char:String = this.text.substr(index,1);
if(char == " "){
colorIndex = 0;
}else{
tf.color = ar[colorIndex];
trace(index + "-" +ar[colorIndex]);
this.setTextFormat(tf,index,index+1);
colorIndex++;
if(colorIndex > ar.length-1){
colorIndex = ar.length-1;
}
}
index++;
}
}
}
}
this how you implement it.Create a new AS3 Fla and assign this as base class:
package {
import flash.display.MovieClip;
import flash.text.TextField;
import flash.text.TextFieldType;
public class MyClass extends MovieClip {
var tf:ColorTextField = new ColorTextField();
public function MyClass() {
// constructor code
tf.width = 500;
tf.text = "12345";
this.addChild(tf);
}
}
}
does not matter where you input the new text
Objective-C would not allow you to run the following code:
myShape.origin.x = 50
This made it easy to detect changes in the origin, since someone using your class was forced to write myShape.origin = newOrigin, and thus you could easily tie in to the setter of this property.
Swift now allows you to perform the original, formerly-disallowed code. Assuming the following class structure, how would you detect the change to the origin in order to execute your own code (e.g. to update the screen)?
struct Point {
var x = 0
var y = 0
}
class Shape {
var origin: Point = Point()
}
Update: Perhaps I should have been more explicit, but assume I don't want to modify the Point struct. The reason is that Shape is but one class that uses Point, there may very well be hundreds of others, not to mention that the origin is not the only way a Point may be used.
Property observers (willSet and didSet) do fire when sub-properties of that property are changed. In this case, when the x or y values of the Point structure change, that property will be set.
Here is my example playground code:
struct Point : Printable
{
var x = 0
var y = 0
var description : String {
{
return "(\(x), \(y))";
}
}
class Shape
{
var origin : Point = Point()
{
willSet(newOrigin)
{
println("Changing origin to \(newOrigin.description)!")
}
}
}
let circle = Shape()
circle.origin.x = 42
circle.origin.y = 77
And here is the console output:
Changing origin to (42, 0)!
Changing origin to (42, 77)!
Doesn't this work?
class Shape {
var origin: Point {
willSet(aNewValueForOrigin) {
// pre flight code
}
didSet(theOldValueOfOrigin) {
// post flight code
}
}
}
Edit: revisited code and added name of arguments to reflect what to expect.
You can use Property Observers also works for structs
Link to the part on the ebook
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
println("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
println("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
Use didSet, e.g.,
struct Point {
var x = 0
var y: Int = 0 {
didSet {
println("blah blah")
}
}
}
class Shape {
var origin: Point = Point()
}
let s = Shape()
s.origin.y = 2
I have two air applications and installed them in desktop and executed them and two air processes are listed in taskbar manager.Now how can I execute some method of one air application from another air application?
Use LocalConnection.
You can Host a Connection in one AIR application and connect from the the other AIR guy... From there - you can call methods.
BEWARE: LocalConnection can be a little tricky and odd (for example, connections are global and the names can't overlap).
From the Example Doc listed above....
// Code in LocalConnectionSenderExample.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.net.LocalConnection;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.events.StatusEvent;
import flash.text.TextFieldAutoSize;
public class LocalConnectionSenderExample extends Sprite {
private var conn:LocalConnection;
// UI elements
private var messageLabel:TextField;
private var message:TextField;
private var sendBtn:Sprite;
public function LocalConnectionSenderExample() {
buildUI();
sendBtn.addEventListener(MouseEvent.CLICK, sendMessage);
conn = new LocalConnection();
conn.addEventListener(StatusEvent.STATUS, onStatus);
}
private function sendMessage(event:MouseEvent):void {
conn.send("myConnection", "lcHandler", message.text);
}
private function onStatus(event:StatusEvent):void {
switch (event.level) {
case "status":
trace("LocalConnection.send() succeeded");
break;
case "error":
trace("LocalConnection.send() failed");
break;
}
}
private function buildUI():void {
const hPadding:uint = 5;
// messageLabel
messageLabel = new TextField();
messageLabel.x = 10;
messageLabel.y = 10;
messageLabel.text = "Text to send:";
messageLabel.autoSize = TextFieldAutoSize.LEFT;
addChild(messageLabel);
// message
message = new TextField();
message.x = messageLabel.x + messageLabel.width + hPadding;
message.y = 10;
message.width = 120;
message.height = 20;
message.background = true;
message.border = true;
message.type = TextFieldType.INPUT;
addChild(message);
// sendBtn
sendBtn = new Sprite();
sendBtn.x = message.x + message.width + hPadding;
sendBtn.y = 10;
var sendLbl:TextField = new TextField();
sendLbl.x = 1 + hPadding;
sendLbl.y = 1;
sendLbl.selectable = false;
sendLbl.autoSize = TextFieldAutoSize.LEFT;
sendLbl.text = "Send";
sendBtn.addChild(sendLbl);
sendBtn.graphics.lineStyle(1);
sendBtn.graphics.beginFill(0xcccccc);
sendBtn.graphics.drawRoundRect(0, 0,
(sendLbl.width + 2 + hPadding + hPadding), (sendLbl.height + 2), 5, 5);
sendBtn.graphics.endFill();
addChild(sendBtn);
}
}
}
// Code in LocalConnectionReceiverExample.as
package {
import flash.display.Sprite;
import flash.net.LocalConnection;
import flash.text.TextField;
public class LocalConnectionReceiverExample extends Sprite {
private var conn:LocalConnection;
private var output:TextField;
public function LocalConnectionReceiverExample() {
buildUI();
conn = new LocalConnection();
conn.client = this;
try {
conn.connect("myConnection");
} catch (error:ArgumentError) {
trace("Can't connect...the connection name is already
being used by another SWF");
}
}
public function lcHandler(msg:String):void {
output.appendText(msg + "\n");
}
private function buildUI():void {
output = new TextField();
output.background = true;
output.border = true;
output.wordWrap = true;
addChild(output);
}
}
}