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も様子見で…。