メモの日々


2014年02月03日(月) [長年日記]

[shell][howto] 巨大ファイルの先頭付近だけを比較

巨大な2つのファイルの先頭付近だけを比較したいときは、シェルのプロセス置換が使えるのでメモ。プロセス置換はbashとzshなら使えるみたい。

% diff -u <(head -100 a) <(head -100 b)

headの引数を2回書かないとけないのは冗長だなあ。


2014年02月05日(水) [長年日記]

[java] JavaFXで表

久しぶりにJavaFXをいじる。前回から1ヶ月経ってしまった。

JavaFX 2で始めるGUI開発 第5回 リスト、コンボボックス、テーブルを読んだ。テーブルが気になるので試してみた。

できあがり

画面イメージ

名前と値を表示するだけ。値の方は編集可能。

表はデフォルトで縞々になるみたい。行や列が無い部分にもセルが補われて表示されている。

以下ソースコード。

行に表示するクラス

SwingのJTableとは違い行ベースの表を簡単に作れるみたい。次のようなRowクラスを作った。

package table;

public class Row {
    private final String name;
    private int value;

    public Row(String n, int v) {
        name = n;
        value = v;
    }

    public String getName() { return name; }

    public int getValue() { return value; }

    public void setValue(int value) { this.value = value; }
}
  • nameは変更不可で、valueは変更可能にしている。

コントローラクラス

package table;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;

public class TableController implements Initializable {
    @FXML
    private TableView<Row> table;

    @FXML
    private TableColumn<Row, String> nameColumn;

    @FXML
    private TableColumn<Row, Integer> valueColumn;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        nameColumn.setCellValueFactory(
            new PropertyValueFactory<Row, String>("name"));
        valueColumn.setCellValueFactory(
            new PropertyValueFactory<Row, Integer>("value"));
        valueColumn.setCellFactory(
            TextFieldTableCell.<Row, Integer>forTableColumn(
                new IntegerStringConverter()));
    }

    public void setRowList(ObservableList<Row> rowList) {
        table.setItems(rowList);
    }

    @FXML
    public void handleValueCommeted(CellEditEvent<Row, Integer> event) {
        event.getRowValue().setValue(event.getNewValue());
    }
}
  • 表はTableView、列はTableColumnクラスで作れる。これらはFXMLの方で関連付ける。Rowクラスとの関連付けは型パラメータで行っている。
  • initialize()にて、Rowのメソッドと列を関連付けている。文字列ベース。表示用にはcellValueFactory、編集用にはcellFactoryを設定するという理解でよい?cellValueFactoryにはPropertyValueFactoryクラス、cellFactoryにはTextFieldTableCellが生成するクラス使える。まだよく分かっていないな。
  • 表に表示するRowオブジェクトをsetRowList()で設定するようにした。もっとスマートに設定したいけれど。
  • handleValueCommited()は、値列の編集が完了したときに呼ばれる(ようにFXMLを書く)。編集結果を使ってRow#setValue()を呼び出している。

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="300.0"
            xmlns:fx="http://javafx.com/fxml/1"
            xmlns="http://javafx.com/javafx/2.2"
            fx:controller="table.TableController">
  <children>
    <ScrollPane fitToHeight="true" fitToWidth="true"
                AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0"
                AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
      <content>
        <TableView fx:id="table" editable="true" >
          <columns>
            <TableColumn minWidth="25" prefWidth="75"
                         text="名前" fx:id="nameColumn" />
            <TableColumn minWidth="25" prefWidth="75"
                         text="値" fx:id="valueColumn"
                         editable="true" onEditCommit="#handleValueCommeted" />
          </columns>
        </TableView>
      </content>
    </ScrollPane>
  </children>
</AnchorPane>
  • 表の外側にScrollPaneを置いてみた。
  • TableViewの中にTableColumnを置いている。
  • 列のタイトルを設定している。
  • 値列だけ編集可能にしている。

メインクラス

package table;

import java.io.IOException;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Table extends Application {
    private ObservableList<Row> rowList;

    @Override
    public void init() {
        rowList = FXCollections.observableArrayList(
            new Row("壱", 1),
            new Row("弐", 2),
            new Row("参", 3));
    }

    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader loader =
            new FXMLLoader(getClass().getResource("Table.fxml"));
        loader.load();

        TableController controller = loader.getController();
        controller.setRowList(rowList);

        Parent root = loader.getRoot();
	primaryStage.setScene(new Scene(root));
	primaryStage.setTitle("Table");
	primaryStage.show();
    }

    public static void main(String[] args) {
	launch(args);
    }
}
  • init()をオーバーライドし、そこでRowオブジェクトを生成してみた。TableViewに登録するにはObservableListというListを使う必要があって、FXCollectionsクラスを使うと簡単に生成できる。
  • コントローラにRowオブジェクトを渡すため、FXMLLoaderインスタンスを明示的に生成している。FXMLLoader#getController()を使うとコントローラオブジェクトを取得できる。ジェネリックメソッドになっていてキャスト不要。

2014年02月08日(土) [長年日記]

  • ソチオリンピックが開幕した。
  • 関東地方は雪。20年ぶりの大雪とのこと。

[java] JavaFXのバインドを試す

JavaFX 2で始めるGUI開発 第6回 プロパティとバインドを読んだ。バインドは便利そう。

この前作った掛算画面がイベントハンドラではなくバインドを使っても実現できそうなので試してみた。コントローラクラスだけを書き換えて次のようにした。

package hello;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ObservableStringValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;

public class HelloController implements Initializable {
    @FXML
    private TextField leftField;

    @FXML
    private TextField rightField;

    @FXML
    private Label resultLabel;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        resultLabel.textProperty().bind(Bindings.multiply(
            new StringDoubleBinding(leftField.textProperty()),
            new StringDoubleBinding(rightField.textProperty())).asString());
    }

    @FXML
    public void handleKey(KeyEvent event) {}

    static class StringDoubleBinding extends DoubleBinding {
        private final ObservableStringValue source;

        public StringDoubleBinding(ObservableStringValue s) {
            super.bind(s);
            source = s;
        }

        @Override
        protected double computeValue() {
            try {
                return Double.parseDouble(source.getValue());
            } catch (NumberFormatException ex) {
                return 0;
            }
        }
    }
}
  • initialize()にてresultLabelにleftFieldとrightFieldの積をバインドしている。
  • 掛算をBindings.multiply()に任せたのだけれど、そうするにはStringPropertyObservableNumberValueに、NumberBindingObservableValue<? extends String>にそれぞれ変換する必要がある。後者はNumberBinding#asString()でできるけど、前者の変換方法が分からなかった。仕方ないのでDoubleBindingを拡張したStringDoubleBindingクラスを自前で用意した。
  • handleKey()は不要だけれど、以前のFXMLを使いまわしているので残している。

以前とは違い、テキストフィールドの値が数値でないときに結果が0と表示されてしまう。


2014年02月16日(日) [長年日記]

  • 二回続けて週末に大雪。今回の方が積もった。雪かきをして腰を痛めた。
  • ソチオリンピック開催中。これまで角野、上村、フィギュアスケート団体、葛西、加藤、長島、小平、平野、平岡、高梨、伊藤、渡部、岡田、羽生、町田、高橋といった方々が入賞した。

[java] 「JavaFX 2ではじめる、GUI開発」の目次

連載記事のJavaFX 2で始めるGUI開発を全部読んだ。どんどん斜め読みになったけれど。どういうわけか個々の記事への目次がなくて不便なので、現時点での記事一覧をここにメモ。