I have JavaFX TextField in my code and would like to add an action to different events on the TextField.
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.text.Font;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
import javafx.beans.value.ChangeListener;
/* Input from user */
weightTF = new TextField();
weightTF.setMaxWidth(36);
activeInsulinTF = new TextField();
activeInsulinTF.setMaxWidth(36);
VBox inputBox = new VBox();
inputBox.setFillWidth(false);
inputBox.setAlignment(Pos.CENTER);
inputBox.getChildren().add(weightTF);
inputBox.getChildren().add(activeInsulinTF);
inputBox.setSpacing(8);
// Add onAction for the texfields
menuHBox.getChildren().add(inputBox);
weightTF.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
double weight = Double.parseDouble(weightTF.getText());
Main.state.setWeight(weight);
System.out.println("Entered weight: " + weight);
}
});
Today I only get an action when I press enter after writing some text in the TextField. How can I add an action for handling a tab press? Also, how to react when the TextField looses focus with a mouse click?
As I read the documentation it should be possible:
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TextField.html
Hope someone can help me :)
There are a couple of convenience methods to do exactly that, for example
weightTF.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
// do stuff
}
});
this executes whenever a key is pressed in the TextField. You might want to check if the pressed key was a specific one. This can be achieved by
if(event.getCode() == KeyCode.TAB){
// do stuff
}
for example. If you are using NetBeans or some other IDE, you can take a look at the convenience methods by pressing the autocomplete shortcut after having typed "weightTF.", which will show you all of the available methods. The methods I am talking about start with setOn...
Hope that helped :)
It sounds from your question as though you are really interested in knowing when the user moves focus from the text field to another control. This can happen typically if the user presses Tab, or clicks the mouse on another control, though technically this behavior is platform-dependent. It can also happen programmatically.
The problems with using "low-level" event handlers are (1) that in theory you would have to register a mouse listener with all other controls; (2) that you rely on the same keystrokes being used on all platforms for focus traversal; and (3) that if you were to add functionality which required programmatic focus traversal (i.e. you have code like someOtherControl.requestFocus() anywhere), your event listener will not be notified.
The sure-fire way to respond if a text field loses focus is simply to register a listener with its focusedProperty():
weightTF.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (! isNowFocused) {
// text field has lost focus...
System.out.println(weightTF.getText());
}
});
Note also that the Scene has a focusOwnerProperty, which is similarly observable and contains a reference to the node in the scene that currently has focus. You could potentially use this property instead for a more general listener that handled moving focus away from any text field.
Related
When using an fxml file and controller, it is possible to have an initialize method, which runs before the view loads. Similarly, is there a way to run a block of code after the view loads?
To be more specific, I have a Rectangle in the fxml file. I want to call the Rectangle's setFill() , method, from the controller, after the view loads and pass a LinearGradient instance. LinearGradient has properties without setters and doesn't have a parameterless constructor, so I don't think the fill property can be assigned in the fxml file.
I tried putting this code in the constructor of the controller but that results in an error. If possible, I would also like to know what procedure takes place with regards to the controller class when FXMLLoader loads an fxml file (when is a constructor called).
Please take a look at this sample code if necessary:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.shape.Rectangle?>
<Pane fx:controller="sample.RectController" xmlns:fx="http://javafx.com/fxml">
<Rectangle fx:id="rect" height="200.0" width="200.0" />
</Pane>
package sample;
import javafx.fxml.FXML;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
public class RectController{
#FXML Rectangle rect;
{
//code i would like to run but currently results in an error
rect.setFill(new LinearGradient(
0, 0.5, 1, 0.5, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.BLUE),
new Stop(1, Color.RED)
));
}
}
You want your controller to implement a no-arg initialize() method annotated with #FXML (The old way was to implement javafx.fxml.Initializable but as you can see from the docs for that method, you don't need the interface anymore.)
You can't do it in the controller's constructor because the fields haven't been injected yet by the FXMLLoader.
I am trying to programmatically pass focus to a newly created TextField, but for some reason setSelection and setFocus do not work. For example, see my test code below:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="_init()">
<mx:Button click="{tf.setSelection(1,2)}" />
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
public var tf:TextField
private function _init():void{
tf = new TextField();
tf.text = "abcdefghijk";
tf.type = TextFieldType.INPUT;
tf.autoSize = TextFieldAutoSize.LEFT;
var ui:UIComponent = new UIComponent();
ui.addChild(tf);
addChild(ui);
tf.setSelection(0,1);
ui.setFocus();
ui.addEventListener(MouseEvent.MOUSE_DOWN, function():void{
tf.setSelection(0,3);
});
}
]]>
</mx:Script>
</mx:Application>
The only setSelection that does anything is the 0,3 one on MOUSE_DOWN. I assume this all has something to do with the text field receiving focus with the mouse click, but I cannot for the life of me figure out how to do this manually.
setFocus works on components that implement the mx.managers.IFocusManagerComponent. Textfield is not a Flex component and doesn't implement this interface, that's why it doesn't work. If I were you, I would use a TextInput instead seeing that you need an input control
On investigating other classes, motivated by Florian's suggestion, I came across UITextField which subclasses TextField. Though it does not implement the IFocusManagerComponent interface, it does have a setFocus method, which at this moment in time seems to be working.
As an added benefit, it can be added to a container directly, that is, without having to construct a UIComponent parent first.
I am pretty sure that this is totally what i need, however I can not get it to work for some reason. What i would like to do is call an arbitrary component that extends Canvas. Since there may be a variety of components named TestCanvasA, TestCanvasC, TestCanvasC which i won't know till run-time I figured this would be the way to go about it. Here is what i have.
<mx:Script>
<![CDATA[
import component.TestCanvas;
import mx.containers.Canvas;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
private function init(evt:Event):void{
var Type:String="TestCanvas";
var controlClass:Class = getDefinitionByName(Type) as Class;
this.addChild(new controlClass() as Canvas);
}
]]>
</mx:Script>
Any ideas would be awesome!
Give it the fully qualified class name:
var type:String="component.TestCanvas";
var controlClass:Class = getDefinitionByName(Type) as Class;
Also a mere import statement need not include the definition of the class in the compiled SWF unless there are references to the class inside the application. Just declare (need not initialize) a variable of that type somewhere in the SWF to make sure that the definition is indeed included.
var dummy:TestCanvas;
I am trying to create a simple video player SWF using the open source media framework in Flex 4. I want to make it dynamically scale based on the dimensions of the video, input by the user. I am following the directions on the Adobe help site, but the video does not seem to scale properly. Depending on the size, sometimes videos play larger than the space allotted on the webpage, and sometimes smaller. The only way I have been able to get it to work properly is by including a SWF metadata tag hardcoding the width and height, but I can't use that if I want to make the player dynamically sized. My code is :
package {
import flash.display.Sprite;
import flash.events.Event;
import org.osmf.media.MediaElement;
import org.osmf.media.MediaPlayer;
import org.osmf.media.URLResource;
import org.osmf.containers.MediaContainer;
import org.osmf.elements.VideoElement;
import org.osmf.layout.LayoutMetadata;
public class GalleryVideoPlayer extends Sprite {
private var videoElement:VideoElement;
private var mediaPlayer:MediaPlayer;
private var mediaContainer:MediaContainer;
private var flashVars:Object;
public function GalleryVideoPlayer() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
flashVars = loaderInfo.parameters;
mediaPlayer = new MediaPlayer();
videoElement = new VideoElement(new URLResource(flashVars.file));
mediaContainer = new MediaContainer();
var layoutMetadata:LayoutMetadata = new LayoutMetadata();
layoutMetadata.width = Number(flashVars.width);
layoutMetadata.height = Number(flashVars.height);
videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layoutMetadata);
mediaPlayer.media = videoElement;
mediaContainer.addMediaElement(videoElement);
addChild(mediaContainer);
}
}}
I don't know much about flex but i've used an OSMF player called the StrobeMediaPlayback and embedded it onto a html page. There's a javascript bridge which you can call using the ExternalInterface.call() function in actionscript (within the player code).
So I wrote a javascript function to resize the swf (can be done easily using jquery) and called it from actionScript whenever the video had to scale.
See if this helps you.
Is it possible to use the Flex Framework and Components, without using MXML? I know ActionScript pretty decently, and don't feel like messing around with some new XML language just to get some simple UI in there. Can anyone provide an example consisting of an .as file which can be compiled (ideally via FlashDevelop, though just telling how to do it with the Flex SDK is ok too) and uses the Flex Framework? For example, just showing a Flex button that pops open an Alert would be perfect.
If it's not possible, can someone provide a minimal MXML file which will bootstrap a custom AS class which then has access to the Flex SDK?
I did a simple bootstrap similar to Borek (see below). I would love to get rid of the mxml file, but if I don't have it, I don't get any of the standard themes that come with Flex (haloclassic.swc, etc). Does anybody know how to do what Theo suggests and still have the standard themes applied?
Here's my simplified bootstrapping method:
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<custom:ApplicationClass xmlns:custom="components.*"/>
ApplicationClass.as
package components {
import mx.core.Application;
import mx.events.FlexEvent;
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.controls.Button;
public class ApplicationClass extends Application {
public function ApplicationClass () {
addEventListener (FlexEvent.CREATION_COMPLETE, handleComplete);
}
private function handleComplete( event : FlexEvent ) : void {
var button : Button = new Button();
button.label = "My favorite button";
button.styleName="halo"
button.addEventListener(MouseEvent.CLICK, handleClick);
addChild( button );
}
private function handleClick(e:MouseEvent):void {
Alert.show("You clicked on the button!", "Clickity");
}
}
}
Here are the necessary updates to use it with Flex 4:
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<local:MyApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="components.*" />
MyApplication.as
package components {
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.components.Application;
import spark.components.Button;
public class MyApplication extends Application {
public function MyApplication() {
addEventListener(FlexEvent.CREATION_COMPLETE, creationHandler);
}
private function creationHandler(e:FlexEvent):void {
var button : Button = new Button();
button.label = "My favorite button";
button.styleName="halo"
button.addEventListener(MouseEvent.CLICK, handleClick);
addElement( button );
}
private function handleClick(e:MouseEvent):void {
Alert.show("You clicked it!", "Clickity!");
}
}
}
This is a very simple app that does only the basic bootstrapping in MXML. This is the MXML:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCreationComplete()">
<mx:Script source="Script.as" />
</mx:Application>
This is the Script.as:
import mx.controls.Button;
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.core.Application;
private function onCreationComplete() : void {
var button : Button = new Button();
button.label = "Click me";
button.addEventListener(MouseEvent.CLICK, function(e : MouseEvent) : void {
Alert.show("Clicked");
});
Application.application.addChild(button);
}
NOTE: The below answer will not actually work unless you initialize the Flex library first. There is a lot of code involved to do that. See the comments below, or other answers for more details.
The main class doesn't even have to be in MXML, just create a class that inherits from mx.core.Application (which is what an MXML class with a <mx:Application> root node is compiled as anyway):
package {
import mx.core.Application;
public class MyFancyApplication extends Application {
// do whatever you want here
}
}
Also, any ActionScript code compiled with the mxmlc compiler -- or even the Flash CS3 authoring tool -- can use the Flex classes, it's just a matter of making them available in the classpath (refering to the framework SWC when using mxmlc or pointing to a folder containing the source when using either). Unless the document class inherits from mx.core.Application you might run in to some trouble, though, since some things in the framework assume that this is the case.
Yes, you just need to include the flex swc in your classpath. You can find flex.swc in the flex sdk in frameoworks/lib/flex.swc
edit: One more thing: if you're using Flex Builder you can simply create a new ActionScript project, which will essentially do the same as above.