2011年8月19日金曜日

ZK:グリッドに追加した最後の行を必ず見えるようにする

Clients.scrollIntoView(component)メソッドを使うことで、親エレメントをスクロールし、指定したエレメントを見えるようにすることができます。 元ネタ
--- zul ---
<window title="動的に追加した最後の行を必ず見えるようにする方法" border="normal"
                     apply="ctrl.MyCtrl" width="350px">
    <grid height="50px">
        <rows id="rows" />
    </grid>
    <button label="行を追加" id="addBtn" />
</window>
--- java ---
public class MyCtrl extends GenericForwardComposer {
    private Rows rows;
    private static int count=0;
    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
    }

    public void onClick$addBtn(){	
        count++;
        Row row =new Row();
        row.appendChild(new Label("new"+count));
        row.setParent(rows);
        Clients.scrollIntoView(row);		
    }
}

2011年8月9日火曜日

Javaコントローラ内でJavaScriptコードをコールする

元ネタ
JavaのコントローラからJavaScriptのコードを実行させることが必要に なるケースがあるかもしれません。 例えばサーバ・プッシュを使い下記の様な処理をする場合が考えられます。
  • サーバ・サイドでイベントを発行する
  • そのイベントは専用のスレッドで操作される
  • そのスレッドの中からなにがしかのJava Script関数をコールしたい
  • こんな時はこんな風に!! Clients.evalJavaScript("alert('Hello World!')); 簡単でしょ?

    --- zul --
    <window title="JavaコントローラからJavaScript関数をコールする" 
           apply="zkexamples.ViewController2"  border="normal" width="350px">
          <button id="btn" label="click"  />                  
    </window>
    
    --- java ---
    public class ViewController2 extends GenericForwardComposer {
        public void onClick$btn(Event event){
            Clients.evalJavaScript("alert('Hello world!');");	
       }
       public void doAfterCompose(Component comp) throws Exception {
            super.doAfterCompose(comp);
        }	
    }
    

    2011年8月1日月曜日

    ZK: JavaScriptからJavaコントローラのメソッドをコールする

    JavaScriptからコントローラ内のJavaメソッドをコールするときは、JavaScript内で親コンポーネントに対しイベントを送り、親コンポーネントのイベントハンドラでコールしたいJavaメソッドを呼び出すようにします。

  • サーバにイベントを送るJavaScript関数

    function callJavaMethod(){
    zAu.send(new zk.Event(zk.Widget.$(this), 'onLinkClicked', 'Parameter'));
    }

    zk.Widget.$(this) => 親コンポーネント(この場合は "rootwindow"を指す)
    'onLinkClicked' => 送出するイベントを処理するコントローラのイベントハンドラメソッド名
    'Parameter' => イベントハンドラへ渡すパラメータ。(オプション)
    ※イベントハンドラ内で Event event を ForwardEventにキャストし
    getOrigin().getData()でパラメータの値を取得できる。



  • JavaScriptから送出されたイベントのイベントハンドラメソッド

    public void onLinkClicked$rootwindow(Event event){
    someJavaMethod();
    }



    --- zul ---
    <window id="rootwindow"
    title="JavaScriptからJavaコントローラのメソッドをコールする" border="normal"
    apply="zkexamples.calljavafromjavascript.ViewController">
    <html><![CDATA[
    <script type="text/javascript">
    function callJavaMethod(){
    zAu.send(new zk.Event(zk.Widget.$(this), 'onLinkClicked', 'Parameter'));
    }
    </script>
    <a href="#" onClick="callJavaMethod();">Click me</a>
    ]]></html>
    </window>


    --- java ---
    public class ViewController extends GenericForwardComposer {

    // JavaScriptからイベントハンドラを経由してコールされるコントローラのメソッド
    private void callMe() {
    alert("Hello JavaScript, this is Java!");
    }

    // コントローラのイベントハンドラ名の最後に親コンポーネント名をつけること忘れないこと!!
    public void onLinkClicked$rootwindow(Event event){
    ForwardEvent fevent = (ForwardEvent)event;
    System.out.println(fevent.getOrigin().getData());
    callMe();
    }
    }
  • 2011年7月22日金曜日

    ZK: Fileアップロードサンプル

    ZKForum のこのスレッドで紹介されていたヘルパークラスを使い、アップロードされたファイルをサーバに格納するサンプルです。


    簡単な使い方:
    --- zul ---
    <button id="uploadBtn" label="Upload file" upload="true,maxsize=300"/>

    --- java ---
    public void onUpload$uploadBtn(UploadEvent event) throws InterruptedException {
    org.zkoss.util.media.Media media = event.getMedia();
    Medias.saveToFile(media, "/path/to/save");;
    }


    ソース

    ヘルパークラス
    --- Medias.java ---
    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.Reader;
    import java.io.StringReader;

    import org.apache.commons.io.IOUtils;
    import org.zkoss.util.media.Media;


    public class Medias {

    public static File saveToFile(Media media, String path) {
    try {
    File file = new File(path + File.separator + media.getName());
    OutputStream output = new FileOutputStream(file);
    if (media.isBinary()) {
    InputStream input = Medias.asStream(media);
    IOUtils.copy(input, output);
    input.close();
    } else {
    Reader input = Medias.asReader(media);
    IOUtils.copy(input, output);
    input.close();
    }
    output.close();
    return file;
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }

    public static String asString(Media media) {
    try {
    String result = null;
    if (media.isBinary()) {
    InputStream input = Medias.asStream(media);
    result = IOUtils.toString(input);
    input.close();
    } else {
    Reader reader = Medias.asReader(media);
    result = IOUtils.toString(reader);
    reader.close();
    }
    return result;
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }

    private static InputStream asStream(Media media) {
    return new BufferedInputStream(
    media.inMemory() ?
    new ByteArrayInputStream(media.getByteData()): media.getStreamData());
    }

    private static Reader asReader(Media media) {
    return new BufferedReader(media.inMemory() ?
    new StringReader(media.getStringData()) : media.getReaderData());
    }
    }





    ビュー
    --- fileupload.zul ----
    <?page title="ファイルアップロード" contentType="text/html;charset=UTF-8"?>
    <zk>
    <window title="ファイルアップロード" border="normal" apply="sample.ctrl.UploadCtrl ">
    <button id="uploadBtn" label="Upload file" upload="true,maxsize=300" />
    <separator />
    <image id="img" />
    <separator />
    <label id="msgLbl" />

    </window>
    </zk>




    コントローラ
    --- FileUploadCtrl.java ---
    public class FileUploadCtrl extends GenericForwardComposer {
    private Label msgLbl;
    private Image img;

    public void onUpload$uploadBtn(UploadEvent event) throws InterruptedException {
    msgLbl.setValue("");
    org.zkoss.util.media.Media media = event.getMedia();

    if(media == null){
    msgLbl.setValue("ファイルを選択してください。");
    return;
    }

    if (media instanceof org.zkoss.image.Image) {
    org.zkoss.zul.Image image = new org.zkoss.zul.Image();
    image.setContent((org.zkoss.image.Image)media);
    image.setParent(img);
    }

    Medias.saveToFile(media, "/path/to/save");;
    }
    }

    2011年7月16日土曜日

    ZK: コミュニティ・エディションで Captchaを使う

    ZK コミュニティ・エディション(CE)では残念ながらCaptchaコンポーネントを利用することができません。
    しかし SimpleCaptcha を用いることで、CEでも Captchaを簡単に利用することができる方法が ZKforum で紹介されていたのでまとめてみました。

    元ネタ

  • SimpleCaptcha サイトからsimplecaptcha.jarをダウンロードし WEB-INF/libへ配備する。

  • CaptchaUtils クラスを作成する。

    import nl.captcha.Captcha;
    import nl.captcha.backgrounds.GradiatedBackgroundProducer;
    import nl.captcha.text.renderer.ColoredEdgesWordRenderer;

    /**
    * CAPTCHAを作成するユーティリティクラス <br>
    * Captchaは直接 org.zkoss.zul.Imageにロード可能 <br>
    *
    * <pre>
    * Image img = new org.zkoss.zul.Image();
    * img.setContent(CaptchaUtils.getCaptcha());
    *
    * String verifyStr = captcha.getAnswer();
    * </pre>
    *
    * @author Stephan Gerth
    */
    public class CaptchaUtils
    public CaptchaUtils(){
    }

    /**
    * 5桁のキャプチャを作成する
    */
    public static Captcha getCaptcha() {

    Captcha captcha = new Captcha.Builder(140, 50)
    .addText(new ColoredEdgesWordRenderer()).addNoise()
    .addBackground(new GradiatedBackgroundProducer())
    .addBorder()
    .build();

    return captcha;
    }
    }



  • コントローラ クラスを作成する。

    public class CaptchaCtrl extends GenericForwardComposer {
    private static final long serialVersionUID = -804655396850565215L;
    private Image img_captcha;
    private Textbox txt_captcha;
    private Captcha captcha;


    public void onCreate$win(Event event){
    doReCaptcha();
    }

    public void onClick$btn1(Event event){
    if (txt_captcha.getValue().equals(captcha.getAnswer())){
    alert("正しいキャプチャです。");
    } else {
    alert("間違っています!!");
    }
    }

    public void onClick$btn2(Event event){
    doReCaptcha();
    }

    /**
    * キャプチャを再表示する<br>
    *
    */
    private void doReCaptcha() {
    captcha = CaptchaUtils.getCaptcha();
    img_captcha.setContent(captcha.getImage());
    }
    }


  • ZULを作成する。

    <window id="win" border="normal" width="350px"
    title="コミュニティ・エディションでもキャプチャが使えます" apply="ctrl.CaptchaCtrl" >
    <vlayout id="input" width="100%" >
    <hbox>
    <image id="img_captcha" />
    <button label="再表示" id="btn2"/>
    </hbox>
    キャプチャを入力してください。
    <textbox id="txt_captcha" hflex="1" width="250px"/>
    <button label="確認" id="btn1"/>
    </vlayout>
    </window>