Table View のデータは変えず表示だけを変える

Table View のデータはそのままに、表示に装飾を加える。
例えばデータはIntegerだけど表示では単位をつけたい、など。

@Override
public void start(Stage primaryStage) {
    //テーブル用のデータを作成
    final ObservableList<TableDataFormat> list = FXCollections.observableArrayList(
        new TableDataFormat("data1", 1),
        new TableDataFormat("data2", 2),
        new TableDataFormat("data3", 3)
    );
    //カラムの作成
    TableColumn stColumn = new TableColumn("String Column");
    TableColumn intColumn = new TableColumn("Integer Column");
    //データとひも付け
    //PropertyValueFactory の引数は TableDataFormat の変数名と合わせる
    stColumn.setCellValueFactory(new PropertyValueFactory("st"));
    //Table に紐づけたデータは変えず、表示だけを変える
    intColumn.setCellValueFactory(new Callback<CellDataFeatures<TableDataFormat, String>, ObservableValue<String>>(){
        @Override
        public ObservableValue<String> call(CellDataFeatures<TableDataFormat, String> tdf) {
            return new ReadOnlyObjectWrapper(tdf.getValue().getNum() + "%");
        }
    });
 
    stColumn.setPrefWidth(150);
    intColumn.setPrefWidth(140);
 
    final TableView table = new TableView();
    table.getColumns().addAll(stColumn, intColumn);
    table.setItems(list);
    table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
    table.setOnMouseClicked(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent t) {
            System.out.println("aa");
        }
    });
 
    VBox vbox = new VBox();
    vbox.getChildren().addAll(table);
    primaryStage.setScene(new Scene(vbox, 300, 250));
    primaryStage.show();
}
 
//テーブル用のデータクラス
public class TableDataFormat{
    private SimpleStringProperty st;
    private SimpleIntegerProperty num;
 
    public TableDataFormat(String st_, int num_) {
        this.st = new SimpleStringProperty(st_);
        this.num = new SimpleIntegerProperty(num_);
    }
    //アクセサ
    //メソッド名は get/set + 変数名 
    public String getSt() { return st.get();}
    public void setSt(String st_) { st.set(st_);}
    public Integer getNum() { return num.get();}
    public void setNum(int num_) { num.set(num_);}
}

ComboBox

EditableなComboBoxは
TextFieldとButtonが組合わさっている(ように見えるんだけど)が、
TextFieldの上にButtonが覆い被さっているため
右端の文字がButtonの下に隠れて見えなくなる。

CSSで整形する必要が有る

…う〜ん、くだらない。
でもやっとかないと微妙に不便。

@Override
public void start(Stage primaryStage) {
    ComboBox cbox = new ComboBox(FXCollections.observableArrayList("abcdefghijklmn"));
    cbox.setMaxWidth(100.0);
    cbox.setEditable(true);
 
    StackPane root = new StackPane();
    root.getChildren().add(cbox);
 
    Scene scene = new Scene(root, 300, 250);
    scene.getStylesheets().add("comboboxsample/style.css");
 
    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}
.combo-box .text-input{
    -fx-padding: 0 20 0 0;
}

CustomMenuBar

半年ぶりです。
そりゃWordPressのパスワードも忘れるわ。

MenuBarはアイテムとしてMenuしか受け入れない。
またレイアウトの自由もない。
なのでMenuBarの中にLabelやTextFieldを入れることはできないが、
それっぽい物を作ってみた。

CustomMenuBar

やっていることは子供だましで、
ToolBarをMenuBarっぽい外観にしてMenuBarの右側にくっつけている。
勿論画面リサイズにも対応するが、
MenuBarのminWidthを設定しないといけないところがちょっとかっこわるい。

ToolBarなのでボタン等のコントロールも入れられるし、
右寄せなどのレイアウト変更もできる。
そもそも全部Toolbarで作ればって話もあるが。

public void start(Stage primaryStage) {
  primaryStage.setTitle("Hello World!");
  VBox root = new VBox();
  final Scene scene = new Scene(root, 350, 250);
  scene.getStylesheets().add("custommenubar/style.css");
 
  //MenuBar
  final MenuBar menuBar = new MenuBar();
  menuBar.setMinWidth(150);
  Menu fileMenu = new Menu("File");
  Menu editMenu = new Menu("Edit");
  Menu helpMenu = new Menu("Help");
  menuBar.getMenus().addAll(fileMenu, editMenu, helpMenu);
 
  ObjectBinding toolBarWidthProperty = new ObjectBinding() {
    {
      super.bind(scene.widthProperty(), menuBar.widthProperty());
    }
    @Override
    protected Object computeValue() {
      return scene.getWidth() - menuBar.getWidth();
    }
  };
 
  //ToolBar
  ToolBar toolBar = new ToolBar();
  toolBar.setId("tool");
  toolBar.prefHeightProperty().bind(menuBar.heightProperty());
  toolBar.minWidthProperty().bind(toolBarWidthProperty);
  toolBar.prefWidthProperty().bind(toolBarWidthProperty);
  toolBar.maxWidthProperty().bind(toolBarWidthProperty);
 
  Region reg = new Region();
  HBox.setHgrow(reg, Priority.ALWAYS);
  TextField rightEdgeLabel = new TextField();
  toolBar.getItems().addAll(reg, rightEdgeLabel);
 
  HBox menuBarHbox = new HBox(0.0);
  menuBarHbox.getChildren().addAll(menuBar, toolBar);
 
  root.getChildren().add(menuBarHbox);
  primaryStage.setScene(scene);
  primaryStage.show();
}
#tool{
  -fx-padding: 0.0em 0.666667em 0.0em 0.666667em; /* 0 8 0 8 */
  -fx-spacing: 0.166667em; /* 2 */
  -fx-base: derive(#d0d0d0,-70%);
  -fx-background-color: linear-gradient(to bottom, derive(-fx-color,50%), derive(-fx-color,-30%)), -fx-body-color;
  -fx-background-insets: 0, 1 0 1 0;
  -fx-background-radius: 0, 0 ;
}

Java7u25

JJUG CCC 2012 Fall お疲れさまでした

JJUG CCC 2012 Fall に参加しました。
講演者の方々、運営の皆さん、お疲れさまでした。

【拝聴した講演の一言メモ】

・基調講演1 利用されるソフトウェアの作り方 -ITアーキテクトの役割を再考する-
『お客様の中にござ先輩(講演予定者)はいらっしゃいませんか〜?』

・基調講演2 2012年 Java 最新動向のご紹介
『StrutsとTomcatはもうやめよう。』
『(海外は)みんな使ってないですよ(って言えば日本人なら使うのやめるよね)』
『ダメ、絶対。』

・R2-1 Javaプログラムの最適化・安定動作とJavaVMの関係
『言っとくけどGC馬鹿だから』
『メモリリークの原因探るのは難しいよね
 (でもウチの製品なら一発ですぜ)』

・ R1-2 ジェネリクスの基礎と応用
『みなさんジェネリクスわかりますよね
ジェネリクスにも種類があって〜…』
  ごめんなさいわかりません orz

・ R1-3 JavaFX 8.0って何だ!! – JavaFX 最新情報 -
『みなさんテスト聞きに行かなくていいんですか?w』
(同時刻に渡辺修司氏の講演もあり、立ち見が出る人気ぶりだった)
『JavaFX 8.0って何だ!! …JavaFX 8.0って何だ??』

・R3-4 WGPによるHadoopの可視化ソフトウェアをオープンソースで公開しました
コスプレしか覚えてないw

・BOF2-1 JSR 310 “Date and Time API” への招待
講演者が暦についてすごく詳しかった
『リリースされるまでいつ何がどう変更されるかわからんのです』

・BOF1-2 作って学ぶデータベース ~まずスモールデータから始めよう~
『RDBクエリ実行を10日で作ってみたら面白かったからみんなやるといいよ〜』
『そのうちSQL解釈とかもつくってみたいな〜』

【一番の収穫】
JJUG って 『ジェィジャグ』って読むんだ
初めて知った

——————————————————–

若干船こいだセッションもありましたが
おおむねみんな楽しかったですw
本当にお疲れさまでした。

家近かったので懇親会も出れば良かったかな〜と後悔しつつも
知り合いいないのに懇親会なんか出れないノミの心臓がこちらになります。

JavaFX 3 改め JavaFX 8

驚くほどブログから離れてた。

JavaFX は Java7u2 から JavaSE に同梱されている。
つまり JavaFX Runtime をインストールする必要は無い。
Java Runtime さえ入れれば良い。

で、JavaFX の次期メジャーアップデートはJava 8 のリリースと同時に行われるんだが
(JavaSE に同梱されてるんだから当たり前とも言える)、
バージョンは 3 ではなく 8 らしい。
Java のバージョンと合わせたってことだろうか。
Firefox や GoogleChrome もびっくりの飛び級出世だが、
Java 1.2 を Java2SE とか読んだ Oracle(当時はSunか) のネーミングセンスの斜め上加減は
今更驚くことではないかもしれない。

ところでWindows 7 が出た時もしばらく「7ブーム」が続いたが、
今回も「8ブーム」となるだろうか。
Win8 は仮想マシンで使ってみたが、最悪に使いづらかった。
Windows はアップデートを重ねるごとに醜くなる奇怪なOSでござる。
一番好きなバージョンは Windows 2000。

と、話がずれたが。
JavaFX 8 が出る前にもう少しブログ更新して行かないとなぁ。
まぁ単なる自分用メモだからチラ裏でもいいんだけど(^^;

WebView#loadContent

JavaFX はブラウザを内蔵していて、
Web ページを表示することができるのは既に紹介した通り
さらにこいつを使えば任意のHTMLを読ませて表示することができるほか、
JavaScript を実行することもできる。

 
WebView view = new WebView();
final WebEngine engine = view.getEngine();
 
//表示させるHTMLコード
String code = "<html><head>";
//CSSの適用も勿論可能
code = code.concat("<style type='text/css'>");
code = code.concat("table, td, th{ border: 1px solid; border-collapse: collapse;}");
code = code.concat("</style>");
code = code.concat("</head><body>");
code = code.concat("<table>");
code = code.concat("<tr><th>row 1</th><td id='1-1'>data 1</td><td>data 2</td></tr>");
code = code.concat("<tr><th>row 2</th><td>data 1</td><td>data 2</td></tr>");
code = code.concat("</table>");
code = code.concat("</body></html>");
 
//loadContent(String st) から読み込ませる。
engine.loadContent(code);
 
Button getDataBtn = new Button("GetData");
getDataBtn.setOnAction(new EventHandler<ActionEvent>(){
    @Override
    public void handle(ActionEvent t) {
        //JavaScriptの実行
        //返り値がある場合もそのまま受け取れる
        System.out.println(engine.executeScript("document.getElementById('1-1').innerText"));
    }
});
 
VBox vbox = new VBox();
vbox.getChildren().addAll(view, getDataBtn);
primaryStage.setScene(new Scene(vbox, 300, 250));
primaryStage.show();

複雑な段組みの表なんかはJavaFXでは表現しづらいので、結構使える。

Mac OSX Lion
Java7 u4
JavaFX 2.1

TableView

JavaFX 2.0 から TableView が追加された。
JavaFX 1.x には無かったんだよね、テーブル。
信じられないことに。

ソートやD&Dでのカラムの入れ替え、レコードのストライピングにもデフォルトで対応。
カラムの複数選択や編集にも対応している。
あ、下のコードは対応させてないけどね。

 
public void start(Stage primaryStage) {
    //テーブル用のデータを作成
    final ObservableList<TableDataFormat> list = FXCollections.observableArrayList(
            new TableDataFormat("data1", 1),
            new TableDataFormat("data2", 2),
            new TableDataFormat("data3", 3)
            );
    //カラムの作成
    TableColumn stColumn = new TableColumn("String Column");
    TableColumn intColumn = new TableColumn("Integer Column");
    //データとひも付け
    //PropertyValueFactory の引数は TableDataFormat の変数名と合わせる
    stColumn.setCellValueFactory(new PropertyValueFactory("st"));
    intColumn.setCellValueFactory(new PropertyValueFactory("num"));
    //右寄せ
    intColumn.setCellFactory(new Callback<TableColumn, TableCell>() {
    @Override
        public TableCell call(TableColumn col) {
            TableCell cell = new TableCell(){
                @Override
                public void updateItem(Object item, boolean empty){
                    if(item !=null){
                        setText(item.toString());
                    }
                }
            };
            cell.setAlignment(Pos.TOP_RIGHT);
            return cell;
        }
    });
 
    stColumn.setPrefWidth(150);
    intColumn.setPrefWidth(140);
 
    final TableView table = new TableView();
    table.getColumns().addAll(stColumn, intColumn);
    table.setItems(list);
    table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
 
    Button addBtn = new Button("add");
    addBtn.setOnAction(new EventHandler<ActionEvent>(){
        @Override
        public void handle(ActionEvent t) {
            list.add(new TableDataFormat("add_"+(list.size()+1), list.size()+1));
        }
    });
    Button removeBtn = new Button("remove");
    removeBtn.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent t) {
            if(table.getSelectionModel().getSelectedItems() !=null){
                list.removeAll(getUniqueItemList(table.getSelectionModel().getSelectedItems()));
            }
        }
    });
    HBox hbox = new HBox();
    hbox.getChildren().addAll(addBtn, removeBtn);
    VBox vbox = new VBox();
    vbox.getChildren().addAll(table, hbox);
    primaryStage.setScene(new Scene(vbox, 300, 250));
    primaryStage.show();
}
 
//テーブル用のデータクラス
public class TableDataFormat{
    private SimpleStringProperty st;
    private SimpleIntegerProperty num;
 
    public TableDataFormat(String st_, int num_) {
        this.st = new SimpleStringProperty(st_);
        this.num = new SimpleIntegerProperty(num_);
    }
    //アクセサ
    //メソッド名は get/set + 変数名 
    public String getSt() { return st.get();}
    public void setSt(String st_) { st.set(st_);}
    public Integer getNum() { return num.get();}
    public void setNum(int num_) { num.set(num_);}
}
 
//バグ対応
public static ObservableList getUniqueItemList(ObservableList list){
    Set set = new HashSet(list);
    return FXCollections.observableArrayList(set);
}

作り方は、
レコードのクラスを作ってやって、そのリストを登録する感じ。
リストは ObservableList だから、リストを更新すれば Table に反映される。
ワンダホー!

どのプロパティがどのカラムに対応するかは setCellValueFactory でひもづける。
…ここがどうもしっくりこない気がするんだけど。
PropertyValueFactory の引数はデータクラスのプロパティ名を String で指定する。
そしてデータクラス側にはアクセサを用意しておく。
勿論 get/set + プロパティ名で。
プロパティは Simple〇〇Property で用意する必要があって、
アクセサやコンストラクタでキャストしてやる必要がある。
ん〜、なんだこのめんどくささは…。

ここでひとつハマったのが、ProGuard の使用。
ProGuard などの最適化ツールを使うと使用していないメソッドが削除されるが、
ここで作成したアクセサも明示的には使用しないため削除されてしまう。
ProGuardを使うときは最適化(および難読化)はしないように設定すべき。

最後のバグ対応はListViewで少し触れた、getSelectedItems への対応。
これしとかないと挙動が不審だったので (^^;

Mac OSX Lion
Java7 u4
JavaFX 2.1

BarChart

JavaFX はいくつかのグラフを標準で備えている。
棒グラフ、円グラフ、折れ線グラフ、など。

CategoryAxis cAxis = new CategoryAxis();
cAxis.setLabel("Category");
ObservableList cList = FXCollections.observableArrayList("cate1", "cate2");
cAxis.setCategories(cList);
//Number Axis
NumberAxis nAxis = new NumberAxis();
nAxis.setLabel("Number");
//Series
XYChart.Series<String, Number> series1 = new XYChart.Series<>();
series1.setName("series1");
series1.getData().add(new XYChart.Data(cList.get(0), 30));
series1.getData().add(new XYChart.Data(cList.get(1), 35));
XYChart.Series<String, Number> series2 = new XYChart.Series<>();
series2.setName("series2");
series2.getData().add(new XYChart.Data(cList.get(0), 20));
series2.getData().add(new XYChart.Data(cList.get(1), 25));
XYChart.Series<String, Number> series3 = new XYChart.Series<>();
series3.setName("series3");
series3.getData().add(new XYChart.Data(cList.get(0), 10));
series3.getData().add(new XYChart.Data(cList.get(1), 15));
 
BarChart<String, Number> chart = new BarChart<>(cAxis, nAxis);
chart.setTitle("Bar Chart");
chart.getData().addAll(series1, series2, series3);
 
primaryStage.setScene(new Scene(chart, 300, 250));
primaryStage.show();

横向きにするには

BarChart<String, Number>

BarChart<Number, String>

にして(データをそれに合わせて)やればいい。

//Category Axis
CategoryAxis hcAxis = new CategoryAxis();
hcAxis.setLabel("Category");
ObservableList hcList = FXCollections.observableArrayList("cate1", "cate2");
hcAxis.setCategories(hcList);
//Number Axis
NumberAxis hnAxis = new NumberAxis();
hnAxis.setLabel("Number");
//Series
XYChart.Series<Number, String> hseries1 = new XYChart.Series<>();
hseries1.setName("series1");
hseries1.getData().add(new XYChart.Data(30, hcList.get(0)));
hseries1.getData().add(new XYChart.Data(35, hcList.get(1)));
XYChart.Series<Number, String> hseries2 = new XYChart.Series<>();
hseries2.setName("series2");
hseries2.getData().add(new XYChart.Data(20, hcList.get(0)));
hseries2.getData().add(new XYChart.Data(25, hcList.get(1)));
XYChart.Series<Number, String> hseries3 = new XYChart.Series<>();
hseries3.setName("series3");
hseries3.getData().add(new XYChart.Data(10, hcList.get(0)));
hseries3.getData().add(new XYChart.Data(15, hcList.get(1)));
 
BarChart<Number, String> hchart = new BarChart<>(hnAxis, hcAxis);
hchart.setTitle("Horizontal Bar Chart");
hchart.getData().addAll(hseries1, hseries2, hseries3);
 
primaryStage.setScene(new Scene(hchart, 300, 250));
primaryStage.show();

グラフの色や角の曲がり具合はCSSから編集することができる。

Mac OSX Lion
Java7 u4
JavaFX 2.1

Mac + JavaFX2.1

Macに Java7u4 と JavaFX2.1、NetBeans 7.1.2 を入れた。
JavaFX2.1 は Java7u4 JDK を入れると勝手に入ってくれる。
いままでVirtualBoxで書いてたので、ずいぶん楽になった。

ちょっと戸惑ったのがインテリジェンス(コード補完)。
Windows だとCtrl + space でできるんだけど、
MacだとSpotlightになってしまう。
Mac ではCommand + ¥ でできるみたい。
import の自動追加は Command + Shift + i。
うん、ちょっと使いづらい…。

JavaFX 2.1 & Java7 u4

JavaFX 2.1 および Java7 u4 がリリースされた。
JavaFX 2.1 は予定よりずいぶん早いリリースになる。

JavaFX に関連して個人的に大きいポイントは以下。

・Mac OSX 対応(10.7 以降)
・StackBar Chart などのコンポーネントの追加
・JavaFX Runtime の自動インストール

https://blogs.oracle.com/java/entry/five_update_java_releases

自動インストールに関しては、
jre7 u4のオンラインインストールを選択すると
JavaFX 2.1 のランタイムも一緒にインストール(アップデート)される。
オフラインインストールだとされないみたい。

JavaFX 2.0.3 で作ったアプリは 2.1 でも動いてる。
TableView のカラム幅が最初狭まっているところが若干見つかってるけど。

合わせて NetBeans も 7.1.2 がリリース。
内容は Mac 対応など。

というわけで、MacでVirtualBox動かしながらSS撮ってたけど
Mac 環境構築しようかな。
Mac 版はまだバグが残ってるみたいだけど。

Go back to top