JavaFXで簡単ファイルマネージャを再現してみた

JavaFXの練習用途で作ってみた。

機能的にはたったこれだけなのですが、Java でデスクトップアプリケーションを書くときには重宝しそうですね。

ということで、簡単ファイルマネージャーを作ってみました。ディレクトリにあるファイルの一覧を表示して、ダブルクリックするとオープンするというものです。。

Java SE 6 じゃじゃ馬ならし Desktop


Swingプログラミング経験がないので適当ですが、こんな感じで似せた動きは出来ているかなと。
ファイルアイコン、フォルダアイコンは適当に用意し、このプログラムの作業フォルダに置いてください。

import javafx.ui.*;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.lang.System;
import javax.swing.UIManager;

//--------------- SimpleFileManager class definition ------------------
class SimpleFileManager {
    attribute current : File;
    attribute files : String*;
    attribute selected : Integer;
    attribute errorMsg : String;
    private operation sortFileName();
}

operation SimpleFileManager.sortFileName() {
    System.err.println("current = {current.getCanonicalPath()}");
    System.err.println("# of files = {sizeof current.listFiles()}");
    var fileList:File* = select file from file in current.listFiles() where file.isDirectory();
    for (file in current.listFiles()) {
        if (not file.isDirectory()) {
            insert file as last into fileList;
        }
    }
    
    System.err.println("sorted files = {sizeof fileList}");
    var fileNames:String* = foreach (file in fileList) file.getName();
    if (current.getParentFile().exists()) {insert ".." as first into fileNames;}
    return fileNames;
}

//attribute SimpleFileManager.files = bind current.list();
//attribute SimpleFileManager.files = bind fileSorter();

trigger on SimpleFileManager.current[oldValue] = newValue {
    System.err.println("dir is changed from \"{oldValue.getPath()}\" to \"{newValue.getPath()}\" ");
//    SimpleFileManager.files = fileSorter();
    this.errorMsg = " ";
    this.files = sortFileName();
}
//--------------- End of SimpleFileManager class definition ------------------


operation getIcon(current:File, fileName:String) {
    var file:File = new File(current, fileName);
    //System.err.println("path = {file.getAbsolutePath()}, isDir? = {file.isDirectory()}");
    var iconFile = new File(if file.isDirectory() then "folder.gif" else "file.gif");
    return iconFile.toURI();
}


//----------------- main --------------------
if (Desktop.isDesktopSupported() == false) {
    System.err.println("Desktop is not supported for your system.");
    System.exit(1);
}
var desktop = Desktop.getDesktop();

var manager = SimpleFileManager {
    current : new File(".").getCanonicalFile()
};
System.err.println(manager.current.getPath());

var frame = Frame {
    title : "Simple File Manager"
    content : BorderPanel {
        top : SimpleLabel {
            text : bind manager.current.getAbsolutePath()
        }
        center : ListBox {
            selection : bind manager.selected
            
            cells : bind foreach (file in manager.files)
                            ListCell {
                                text : bind "<html><table><tr><td><img src='{getIcon(manager.current, file)}' /><td><td>{file}<td><tr><table><html>
"
                                //text : bind file
                            }
            
            action : operation () {
                if(manager.selected < 0 or manager.selected > sizeof manager.files) {
                    return;
                }
                var file = new File(manager.current, manager.files[manager.selected]);
                System.err.println("selected file = {file.getAbsolutePath()}");
                try {
                    if (file.isDirectory()) {
                        System.err.println("{file.getAbsolutePath()} is a directory.");
                        manager.current = file.getCanonicalFile();
                    } else if (file.isFile()) {
                        System.err.println("{file.getAbsolutePath()} is a file.");
                        desktop.open(file);
                    } else {
                        System.err.println("{file.getAbsolutePath() } : exists? = {file.exists()}");
                    }
                } catch (e:IOException) {
                    manager.errorMsg = e.getMessage();
                }
            }
            
        }
        bottom : SimpleLabel {
            text : bind manager.errorMsg
        }
    }
    
    width : 300
    height : 500
};

frame.visible = true;

以下、JavaFXについての感想。

簡単だと思ったこと:

  • Swingに比べてコンポーネントの配置は簡単に書ける。宣伝的というやつか。
  • bindオペレータにより、値の変更を画面に反映させることが非常に簡単

難しいと思ったこと:

  • 配列に要素1つを加えて(..フォルダ)bindさせることはできず、triggerを使う必要がある
  • Iconとテキストの両方を配置する場合、JLabel相当がなく、HTML構文を使う必要あり

改善要望

個人的には、Consumer JREの高速起動、Nimbus LAF、ダイアログなしで動く仕組み(署名ありでOKだったかな?)が整えば、ようやくFlashと同じ土台に立てるのかなと思う。Flashの方が圧倒的に強い立場にいるけれど、少しだけJavaFXも様子見で…。