Hatena::ブログ(Diary)

tomoTakaの日記

2014-05-10

Simple WebView Sample

The following code is a very simple example how to start loading the url or cancel it.
You can get more details information hereno title

  • OS version

f:id:tomoTaka:20140506171322p:image:w160

f:id:tomoTaka:20140506171355p:image:w360

  • Figure1(During loading the URL)

f:id:tomoTaka:20140506172420p:image:w360

  • Figure2(When loading has Completed)

f:id:tomoTaka:20140506172441p:image:w360

  • code1(FXMLDocumentController.java)

The following code shows how to start or cancel loading a url.
This is very easy. First you get the WebEngine and use the load method to get the Web Page.
Since loading happens on a background thread, use the Worker to cancel it.

    public void initialize(URL url, ResourceBundle rb) {
...
        this.engine = webView.getEngine(); // *** 1.get the WebEngine from WebView
...
    }
    @FXML private void loadURL(Event event){
        startLoadState.apply();
        String url = urlText.getText();
        this.engine.load(url);   // *** 2.to start loading the url
    }
    @FXML private void cancelLoad(Event event) {
        startCancelState.apply();
        this.engine.getLoadWorker().cancel();  // *** 3.to cancel loading the url
    }

Thanks to bindings, it is very easy to show progress on indicator.(see figure1)

    public void initialize(URL url, ResourceBundle rb) {
...
        // binding the progressIndicator to the Web LoadWorker
        this.indicator.progressProperty().bind(this.engine.getLoadWorker().progressProperty());
...
    }

You need to add the ChangeListener for changing the state of the screen.
The following code implements SUCCEEDED, CANCELLED and FAILED states, but you can use more.
(FYR seehttp://docs.oracle.com/javafx/2/api/)

    public void initialize(URL url, ResourceBundle rb) {
…
        this.engine.getLoadWorker().stateProperty().addListener(
                (ov, oldState, newState) -> {
                    switch (newState){ 
                        case SUCCEEDED:
                            loadCompletedState.apply();
                            loadCompletedState.setScreenCommonState(this);
                            break;
                        case CANCELLED:
                            loadCanceledState.apply();
                            loadCanceledState.setScreenCommonState(this);
                            break;
                        case FAILED:
                            loadFailedState.apply();
                            loadFailedState.setScreenCommonState(this);
                            break;
                    };
                });
…

I just want to use FunctionalInterface to learn how to use it.
I am not sure if this is the right way.But it is fun to use JavaSE8.

@FunctionalInterface
interface LoadingState{
    void apply();
    default void setScreenCommonState(FXMLDocumentController controller) {
        controller.urlText.setDisable(false);
        controller.loadButton.setDisable(false);
        controller.cancelButton.setDisable(true);
        controller.indicator.setVisible(false);
    }

To change the state of controllers by implementing above FunctionalInterface.

    public void initialize(URL url, ResourceBundle rb) {
        setLoadingState();
…
    }

    private void setLoadingState() {
        initState = () -> {
            loadState.setText("");            
            webView.setVisible(false);
        };
        startLoadState = () -> {
            urlText.setDisable(true);
            loadButton.setDisable(true);
            cancelButton.setDisable(false);
            loadState.setTextFill(Color.BLACK);
            loadState.setText("loading...");            
            webView.setVisible(false);
            indicator.setVisible(true);
        };
        startCancelState = () -> {
            cancelButton.setDisable(true);
            loadState.setTextFill(Color.BLACK);
            loadState.setText("cancelling....");            
        };
        loadCompletedState = () -> {
            loadState.setTextFill(Color.BLACK);
            loadState.setText("completed!");            
            webView.setVisible(true);
        };
        loadFailedState = () -> {
            loadState.setTextFill(Color.RED);
            loadState.setText("failed!!!");            
            webView.setVisible(false);
        };
        loadCanceledState = () -> {
            loadState.setTextFill(Color.ORANGE);
            loadState.setText("canceled!");            
            webView.setVisible(false);
        };
    }

  • code2(FXMLDocument.fxml)
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>

<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxsimplewebview.FXMLDocumentController">
    <children>
        <WebView fx:id="webView" layoutX="15.0" layoutY="86.0" prefHeight="497.0" prefWidth="773.0" />
        <Label layoutX="30.0" layoutY="33.0" text="URL:" />
        <TextField fx:id="urlText" layoutX="68.0" layoutY="28.0" prefHeight="26.0" prefWidth="592.0" />
        <Button fx:id="loadButton" layoutX="700.0" layoutY="28.0" mnemonicParsing="false" onMouseClicked="#loadURL" prefHeight="26.0" prefWidth="82.0" text="load" />
        <Label fx:id="loadState" layoutX="102.0" layoutY="65.0" prefHeight="16.0" prefWidth="500.0" />
        <Label layoutX="27.0" layoutY="65.0" prefHeight="16.0" prefWidth="75.0" text="load state:" />
        <ProgressIndicator fx:id="indicator" layoutX="163.0" layoutY="119.0" prefHeight="148.0" prefWidth="218.0" progress="0.0" />
        <Button fx:id="cancelButton" layoutX="673.0" layoutY="60.0" mnemonicParsing="false" onMouseClicked="#cancelLoad" prefHeight="26.0" prefWidth="111.0" text="cancel load" />
    </children>
</AnchorPane>

The above code2 is created by Scene Builder.
f:id:tomoTaka:20140510212904p:image:W380

  • code3(JavaFXSimpleWebView.java)

The main entry point for JavaFX application is here.

public class JavaFXSimpleWebView extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        // *** load the FXML(code2)
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        Scene scene = new Scene(root);
        stage.setTitle("Simple WebView Sample");
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);  // *** 
    }
}

Assigned the project using Flex, so I created the HTML with swf file before. 2014-05-06 - tomoTakaの日記
I was a little curious about if HTML with Flex works on JavaFX WebView.
It does not work, but it is very fun to try something new by myself.
f:id:tomoTaka:20140506173418p:image:w430
whole code is herehttps://github.com/tomoTaka01/JavaFXSimpleWebView
just keep coding... ;-)

2014-05-06

HTML内でSWFファイルにメッセージを送信(Gradleでswfファイルをコンパイル)

HTMLファイルよりswfobjectを使用してswfファイルに引数を渡して、swfファイルで渡された引数を表示するSampleを作成してみました。
swfコンパイルは、FlashBuilderを使わずにGradle(Ant)で実行。

  • 初期表示の画面

f:id:tomoTaka:20140506075611p:image:w300

  • [send message to Flex]ボタンをクリックした画面

HTML内で入力したメッセージ「greeting!」がFlex内で表示。
f:id:tomoTaka:20140506075735p:image:w280

  • Flex内で[Message Rotate]ボタンをクリックした画面

f:id:tomoTaka:20140506075753p:image:w300

  • 作成したファイルの構成(以前にJavaFXで作成したアプリで表示)

f:id:tomoTaka:20140506075810p:image:w470

  • code1(Sample.html)

swfobjectはno titleよりdownload
swfobjectのembedSWFメソッドを使って「Sample.swf」にflashVarsとしてメッセージを送信。
初期表示時は固定文字「hello flex!」、「send message to Flex」ボタンをクリック時は「message」に入力された値を送信
「Sample.swf」ファイルは、outputタグ「id:result」に表示するように指定

<!DOCTYPE html>
<html>
    <head>
        <title>HTML with Flex Sample by swfobject</title>
        <meta charset="UTF-8">
        <script src="../js/lib/jquery.js"></script>
        <script src="../js/lib/swfobject.js"></script>
        <script>
            $(function(){
                var flashVars = {message:'hello flex!'};   // *** 初期メッセージ指定
                swfobject.embedSWF("../Flex/swf/Sample.swf", 'result',
                '300', '200', '10.0.0', '', flashVars);
                $("#sendBtn").click(function(){
                    var msg = $("#message").val();   // *** 入力メッセージ指定
                    var flashVars= {message: msg};
                    swfobject.embedSWF("../Flex/swf/Sample.swf", 'result',
                        '300', '200', '10.0.0', '', flashVars);
                });
            });
        </script>
    </head>
    <body>
        <div>
            <label>Message:</label>
            <input type="text" id="message" />
            <input type="button" id="sendBtn" value="send message to Flex" />
        </div>
        <div style="width:320px; padding-left:10px; background-color: aqua;">
            <label>Flex comes here</label>
            <output id="result"></output>
        </div>
    </body>
</html>
  • code2(Sample.mxml)

画面ロード後に「init」メソッドを実行するように指定(initメソッドはcode3に記述)
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/effects/Rotate3D.htmlを参考にRotateを実装

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   creationComplete="init()"
			   >
	<fx:Declarations>
        <s:Rotate3D id="rotateEffect" target="{messageLabel}"
            angleXFrom="0" angleXTo="180" angleYFrom="0" angleYTo="180"
            duration="1000" autoCenterTransform="true"
            effectStart="rotateButton.enabled=false" effectEnd="rotateButton.enabled=true" />
	</fx:Declarations>
	<fx:Script source="../script/Sample.as" />
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		@namespace mx "library://ns.adobe.com/flex/mx";
		s|Label {
			font-size : 18pt;
			color : Blue;
		}
	</fx:Style>
	<s:VGroup paddingTop="10" gap="5" >
		<s:Label id="label" width="100%" />
		<s:Label id="messageLabel" width="100%" text="unrecieved" paddingLeft="50" />
        <s:Button id="rotateButton" label="Message Rotate" />
	</s:VGroup>
</s:Application>
  • code3(Sample.as)

HTMLより「embedSWF」メソッドで渡された値は「FlexGlobals.topLevelApplication.parameters」で取得
HTML内の「flashVars」で「message」としているのでここでも「message」を指定

private function init():void {
	this.label.text = "Message is ";
    var msg:String = FlexGlobals.topLevelApplication.parameters.message;  // *** HTMLよりmessage取得
    messageLabel.text = msg;
    // message rotate button
    this.rotateButton.addEventListener(MouseEvent.CLICK, function(e:Event):void {
        var msg:String = FlexGlobals.topLevelApplication.parameters.message;   // *** HTMLよりmessage取得
        messageLabel.text = msg;
        rotateEffect.play();
    });
}

mxmlcantタスクno titleを参考
「flexTasks.jar」は以前http://d.hatena.ne.jp/tomoTaka/20140410にdownloadしたsdk配下よりコピー

<?xml version="1.0" encoding="utf-8" ?>
<project name="My Sample Builder" basedir="." >
    <taskdef resource="flexTasks.tasks" classpath="${basedir}/lib/flexTasks.jar" />
    <property name="FLEX_HOME" value="/Users/tomo/Flex4.12" />
    <property name="APP_ROOT" value="Flex" />
    <property name="DEPLOY_DIR" value="swf" />

    <target name="compile">
        <mxmlc file="${APP_ROOT}/view/Sample.mxml" keep-generated-actionscript="true" output="${APP_ROOT}/${DEPLOY_DIR}/Sample.swf" >
            <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml" />
            <source-path path-element="${FLEX_HOME}/frameworks" />
        </mxmlc>
    </target>
</project>
  • build.gradle
   ant.importBuild 'build.xml'

第17章 GradleからAntを使うを参考に、Gradleも初心者なので[AntBuilder]を使ってmxmlcでSample.mxmlコンパイル

gradle compile

f:id:tomoTaka:20140506084538p:image:w360

一応gitにアップしましたno title
Flex、Gradleとかまだまだ初心者ですが、いろいろ挑戦していけたらと思っています!

2014-04-13

closure sample

Flex(ActionScript)でクロージャーを実装したので、ちょっとメモ。
JavaScriptでの実装とちょっと違っていて?思った以上にはまりました。(汗)

「add1」「add2」のボタン毎に持っている値を「add1」ボタンをクリックした時は「1」加算、「add2」ボタンをクリックした時は「2」加算して画面の「value」ラベル右側(赤字箇所)に表示
f:id:tomoTaka:20140413141628p:image:w430

add1ボタンを3回クリック後
f:id:tomoTaka:20140413142608p:image:w180

画面1の状態で、add2ボタンを1回クリック後
(赤字箇所の数値がadd2ボタンを1回しかクリックしていないので「2」と表示)
f:id:tomoTaka:20140413142637p:image:w180

add1ボタンを3回クリック後
f:id:tomoTaka:20140413142652p:image:w180

画面3の状態で、add2ボタンを1回クリック後
f:id:tomoTaka:20140413142706p:image:w180

<!DOCTYPE html>
<html>
    <head>
        <title>Adder Sample(java script)</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="js/libs/jquery/jquery.js" ></script>
        <script>
            $(function() {
                $('#result').text('0');
                adder = function(addVal){
                    var i = 0;  // <-- 変数「i」は、add1、add2のボタン毎に保持
                    return function() {
                            i += addVal;
                            $('#result').text(i);
                        };
                };
                $('#add1Button').click(adder(1));
                $('#add2Button').click(adder(2));
                $('#addDiv').click(function(event){
                    var tmp = $('#history').text();
                    $('#history').text(tmp + event.target.id + "\n");
                });
            });
        </script>
    </head>    
    <body>
        <div style="font-size: 16px; color:blue">Adder Sample(java script)</div>
        <div>
            <label>value:</label>
            <output id="result" style="color: red; font-weight: bold"></output>
        </div>
        <div id="addDiv">
            <input type="button" id="add1Button" value="add1" />
            <input type="button" id="add2Button" value="add2" />
        </div>
        <div style="margin-top: 10px">
            <label>click history</label>
            <br/>
            <textarea id="history" style="height: 100px;"></textarea>
        </div>
    </body>
</html>
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="100" minHeight="100"
			   creationComplete="init()"
			   >
	<s:layout>
		<s:VerticalLayout gap="10" paddingTop="10" paddingLeft="10" />
	</s:layout>
	<fx:Style>
		@namespace s "library://ns.adobe.com/flex/spark";
		@namespace mx "library://ns.adobe.com/flex/mx";
		#result {
			color:red;
			font-weight: bold;
		}
	</fx:Style>
	<fx:Script source="includes/Adder.as" />
	<fx:Declarations>
	</fx:Declarations>
	<s:Label text="Adder Sample(action script)" fontSize="14" color="blue" />
	<s:HGroup gap="5">
		<s:Label text="value:" />
		<s:Label id="result" />
	</s:HGroup>
	<s:HGroup gap="5" id="addDiv">
		<s:Button id="add1Button" label="add1" />
		<s:Button id="add2Button" label="add2" />
	</s:HGroup>
	<s:VGroup paddingTop="10">
		<s:Label text="click history"/>
		<s:TextArea id="history" height="100" />
	</s:VGroup>
		
</s:Application>

add1ボタンで使用している「add」メソッドないでは、「this」は「global object」?なので「this.result.text = String(ix)」では画面に表示されない。
add2ボタンで使用している「addWithObject」メソッドでは、引数に自分自身である「this」を追加し、引数の「objThis」を使用。

import flash.events.MouseEvent;

import mx.controls.Alert;
private function init():void {
	this.result.text = "0";
	this.add1Button.addEventListener(MouseEvent.CLICK, add(1));
	this.add2Button.addEventListener(MouseEvent.CLICK, addWithObject(2, this)); // <-*1*ここで引数にthisを指定
	this.addDiv.addEventListener(MouseEvent.CLICK, addHistory);
}
private function add(addVal:int):Function {
	var i:int = 0;
	return function() {
//		Alert.show(this.toString());
		i += addVal;
		// this does not work because this has object global		
//		this.result.text = String(ix); 
		setValue(i);
	}
}
private function setValue(ix:int):void {
	this.result.text = String(ix);
}

private function addWithObject(addVal:int, objThis:Object):Function {
	var i:int = 0;
	return function(e:MouseEvent):void {
		i += addVal;
		objThis.result.text = String(i); // <-- *1*引数で渡されたthisを使って画面表示
	}
}
private function addHistory(event:MouseEvent):void {
	var tmp:String = this.history.text;
	this.history.text = tmp + event.target.id + "\n";
}

参考までに

  • Alertを使用して「this」を確認

f:id:tomoTaka:20140413145026p:image:w180

上記実装をgistにアップしました。
Action Script Sample
Java Script Sample

まだまだ初心者です。記載内容に誤りなどありましたら、ご指摘いただけると嬉しいです。^^;;;

2014-04-10

Flex SDK4.12 mxmlcコマンドでコンパイル

前回2014-04-07 - tomoTakaの日記のFlashBuilderのSDKでは、mxmlcコマンドでコンパイルするために32bit版のjreが必要だったので、Apache Flex® - SDK InstallerからFlexSDKの最新バージョン4.12をインストール。

  • エラー画面

f:id:tomoTaka:20140410080126j:image:w360

  • インストーラー

f:id:tomoTaka:20140409083219p:image:W240

  • MAC OS X のバージョン(10.9にも対応してました。)

f:id:tomoTaka:20140407073904p:image:w120

f:id:tomoTaka:20140407073922p:image:w360

  • 上記インストーラをdownloadして実行すると以下のエラーが発生

f:id:tomoTaka:20140409083235p:image:w240

  • セキュリティの設定を変更

f:id:tomoTaka:20140410074648p:image:w300
f:id:tomoTaka:20140409083302p:image:w300

  • インストール開始

f:id:tomoTaka:20140410074915p:image:w300

mxmlc ~/Documents/FlexWorkSpace/src/Test.mxml

f:id:tomoTaka:20140410074931p:image:w480

なんとかコンパイルできた!^^;;;

2014-04-07

First Sample

初めてFlexを使ってみたので、ちょっとメモ。
OSは、MAC OS X 10.9です。
f:id:tomoTaka:20140407073904p:image:medium
Javaのバージョンは8です。
f:id:tomoTaka:20140407073922p:image:w360

まず開発環境のAdobe FlashBuilder4.7をダウンロード(60日間の体験版)
アドビ製品一覧 | Adobe Creative Cloud
AdobeのユーザーIDを作成して、creative cloudをまずdownloadして、そこからFlashBuilderをdownload
f:id:tomoTaka:20140407075308p:image:w240
FlashBuilderで、新規Flexプロジェクトを作成

  • プロジェクト名とフォルダを指定

f:id:tomoTaka:20140407074031p:image:w360

  • とりあえずは「アプリケーションサーバーはなし」で作成

f:id:tomoTaka:20140407074049p:image:w360
これでプロジェクトが作成できます。
「FirstSample」プロジェクトを作成して、とりあえず試してみたいことを実装

  • フォルダ構成

ここでは、2つ「FirstSample.mxml」と「Sample1.as」のみ
f:id:tomoTaka:20140407074003p:image:w240

  • code 1(FirstSample.mxml)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
			   creationComplete="init()"  // ***1.ページ表示時のメソッドをここで指定
			   >
    <fx:Style>
        @namespace s "library://ns.adobe.com/flex/spark";
        @namespace mx "library://ns.adobe.com/flex/mx";
		.myStyleRed {
			color:red
		}
		.myStyleBlue {
			color:blue
		}
        s|Button {
            font-size: 18pt
        }
    </fx:Style>
	<fx:Declarations>
		
	</fx:Declarations>
	<fx:Script>
		<![CDATA[
                        // *** Button1 click 時の処理
			private function method1(val:String):void {
				l1.text=val;
				l2.text=val;
				trace(val);
			}
		]]>
	</fx:Script>
	<fx:Script source="includes/Sample1.as"/>
	<s:layout>
		<s:BasicLayout/>
	</s:layout>
	<s:VGroup paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10">
		<s:HGroup>
			<s:Label id='l1' styleName='myStyleRed' text="label1" />
			<s:Label id='l2' styleName='myStyleBlue' text="label2" />
		</s:HGroup>	
		<s:HGroup>
			<s:Button id="b1" label="Button1" click="method1('Button1 clicked!');" />
			<s:Button id="b2" label="Button2" click="method2('Button2 clicked!');" />
			<s:Button id="b3" label="Button3" />
		</s:HGroup>
	</s:VGroup>
</s:Application>
  • code 2(Sample1.as)
import flash.events.MouseEvent;

import mx.controls.Alert;

import spark.components.Label;

// ***1.ページ表示時の処理
public function init():void{
	this.l1.text="creation completed!";
	this.l2.text="";
	this.b3.addEventListener(MouseEvent.CLICK, method3);  // ***Button3 click時の処理をここで設定
}
// ***Button2 click時の処理
public function method2(val:String):String{
	Alert.show(val);
	this.l1.text=val;
	this.l2.text=val;
	return val;
}
// ***Button3 click時の処理
private function method3(event:MouseEvent):void {
	var ls:Array = [this.l1, this.l2];
	for each(var l:Label in ls){
		l.text = "Button3 clicked!";
	}
}

  • 実行

FirstSample.mxmlで右クリックで、実行->webアプリケーションをクリック

  • 実行結果(初期表示)

1つ目のラベルに「Sample1.as』の#initで実装している「creation completed」が表示される
f:id:tomoTaka:20140407074248p:image

  • Button1をクリック後

FirstSample.mxmlで実装しているScriptのmethod1がcallされてラベルに「Button1 clicked!」が表示される
ラベル1、ラベル2にはそれぞれ、<fx:Style>で指定しているスタイルが適用されて、文字の色が赤と青になる。
またすべてのボタンのフォントサイズもスタイル指定。
f:id:tomoTaka:20140407074315p:image:w360

  • Button2をクリック後

Sample1.asで実装しているmethod2がcallされて、アラート表示されて、ラベルに「Button2 clicked!」が表示される
f:id:tomoTaka:20140407074332p:image:w120
f:id:tomoTaka:20140407074346p:image:w360

  • Button3をクリック後

Sample1.asのinitメソッドで、「Button3」にclick時のメソッド「method3」を登録、method3がcallされてラベルに「Button3 clicked!」が表示される
f:id:tomoTaka:20140407074359p:image:w360
一応、githubにcommitno title
まだまだ始めたばかりですが、少しずつでも実装したことをブログに記載できれば、、、

Flex チュートリアル&記事http://flex.apache.org/index.htmlを参考にしました。
traceでlogが出力できるのですが、debugモードで実行できない?ようでログが出力されていないようです^^;;;