JavaFX 2.2 独自コンポーネントをFXMLで使う

3秒でできます。

1. 独自コンポーネントクラスを作成

public class MyLabel extends Label {

    public MyLabel() {
        super();
        setText("My Label☆");
    }
}

2. FXMLファイルにてimport

<?import dbaccesstest.MyLabel?>

3. FXMLファイルにコンポーネントを配置
(Scene Builderからは独自コンポーネントを扱えなかったので、直接FXMLファイルを編集)

<MyLabel />

完成ー☆

JavaFX 2.2 画面遷移時の値受け渡し。Controllerさん、どうぞ。

こんな感じ。
public static finalで渡す よりいいと思うけれど、果たしてこれが画面遷移時の正解なのか??

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/UpdateScreen.fxml"));
        Scene scene = new Scene((Parent) fxmlLoader.load());// initialize が呼ばれる

        // ロードしたFXMLファイルに関連づくControllerを取得
        final UpdateScreenController controller = (UpdateScreenController) fxmlLoader.getController();
        // Controllerさん、どうぞ。
        controller.setId(customer.getId());

Controller側にSetterを用意しておきます。

public class UpdateScreenController implements Initializable {

   // (中略)
    /**
     * 更新対象CustomerのId
     * 
     * @see Customer
     */
    private Integer id;
    
    public void setId(Integer i) {
        id = i;
    }
}

JavaFX 2.2 FXML利用時のController取得方法

こんな感じ。
Controller取得前にFXMLファイルをロード(fxmlLoader.load())しているのがポイント。
順番が逆だと取得できない。

        // FXMLファイルをロード
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/AlertScreen.fxml"));

        Scene scene = new Scene((Parent) fxmlLoader.load());
        stage.setScene(scene);

        // ロードしたFXMLファイルに関連づくControllerを取得
        final AlertScreenController controller = (AlertScreenController) fxmlLoader.getController();

JavaFX 2.2 TableView プロパティの変更が反映されない

TableView を使っていて困ったのが、データ行追加はイベントとして認識されるけれどプロパティ(Customer.firstName 等)が変更されてもTableViewが更新されないこと。
検索ボタン押下時処理に

こんなんとか

        tableView.getItems().clear();
        List<Customer> cList = CustomerAccess.selectAll();
        tableView.getItems().addAll(cList);

こんなんとか

        List<Customer> cList = CustomerAccess.selectAll();
        ObservableList<Customer> oList = FXCollections.observableArrayList(cList);
        tableView.setItems(oList);

書いても初回の検索結果が表示されたまま。
Debug実行でcListの中身を見ると変更後の値がとれているのに、それがTableViewに反映されない。

http://javafx-jira.kenai.com/browse/RT-22599
を参考に

        tableView.layout();

を挟んだらいけました。ふー。

JavaFX 2.2 TableViewに単一選択のラジオボタン列を表示

見よう見まねで作ったけれど、お作法というか、やり方というか、合ってるのかしらん?

一覧画面から編集画面を開き、編集画面が閉じたタイミングで一覧画面にて再検索します。

package dbaccesstest;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Callback;

/**
 * 一覧画面 Controller
 * 
 * @author denko
 */
public class SearchScreenController implements Initializable {

    @FXML
    private TableView tableView;
    @FXML
    private TableColumn selectColumn;
    @FXML
    private AnchorPane rootPane;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        tableView.setEditable(true);
        Callback<TableColumn, TableCell> cellFactory =
                new Callback<TableColumn, TableCell>() {
                    @Override
                    public TableCell call(TableColumn p) {
                        return new RadioButtonCell();
                    }
                };
        selectColumn.setCellFactory(cellFactory);

        // TableViewをデータ0件で初期化
        ObservableList<Customer> oList = FXCollections.observableArrayList(new ArrayList<Customer>());
        tableView.setItems(oList);
    }

    /**
     * 検索ボタン押下時処理
     * 
     * @param event 
     */    
    @FXML
    private void handleSearchButtonAction(ActionEvent event) {
        search();
    }

    /**
     * 顧客情報一覧検索処理
     */
    private void search() {
        tableView.getItems().clear();
        tableView.layout();// reflesh代わり http://javafx-jira.kenai.com/browse/RT-22599

        List<Customer> cList = CustomerAccess.selectAll();
        tableView.getItems().addAll(cList);
    }

    /**
     * 編集ボタン押下時処理
     * 
     * @param event
     * @throws IOException 
     */    
    @FXML
    private void handleEditButtonAction(ActionEvent event) throws IOException {
        Customer selectedCustomer = null;

        final ObservableList<Customer> items = tableView.getItems();
        for (Iterator<Customer> it = items.iterator(); it.hasNext();) {
            Customer customer = it.next();
            final Boolean selected = customer.getSelected();
            if (selected != null && selected) {
                selectedCustomer = customer;
                break;
            }
        }

        if (selectedCustomer == null) {
            showAlertStage("顧客情報が選択されていません。");
        } else {
            showUpdateStage(selectedCustomer);
        }
    }

    /**
     * アラート画面表示処理
     * 
     * @param message
     * @throws IOException 
     */
    private void showAlertStage(String message) throws IOException {
        Stage stage = new Stage();

        // FXMLファイルをロード
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/AlertScreen.fxml"));

        Scene scene = new Scene((Parent) fxmlLoader.load());
        stage.setScene(scene);

        // ロードしたFXMLファイルに関連づくControllerを取得
        final AlertScreenController controller = (AlertScreenController) fxmlLoader.getController();
        controller.setMessageText(message);

        stage.showAndWait();
    }

    /**
     * 編集画面表示処理
     * 
     * @param customer
     * @throws IOException 
     */
    private void showUpdateStage(Customer customer) throws IOException {
        // 次画面をモーダルで起動
        Stage newStage = new Stage();

        // モーダルで開いてみる
        newStage.initModality(Modality.APPLICATION_MODAL);
        newStage.initOwner(rootPane.getScene().getWindow());

        // FXMLファイルをロード
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/UpdateScreen.fxml"));
        Scene scene = new Scene((Parent) fxmlLoader.load());// initialize が呼ばれる

        // ロードしたFXMLファイルに関連づくControllerを取得
        final UpdateScreenController controller = (UpdateScreenController) fxmlLoader.getController();
        controller.setId(customer.getId());

        newStage.setScene(scene);
        newStage.setOnShowing(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                // 画面が開いたことをControllerに通知
                controller.onShown();
            }
        });
        
        // closeで閉じるとHiddenイベントが発生する
        // http://stackoverflow.com/questions/10212366/javafx-2-0-closing-a-stage-window
        newStage.setOnHidden(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                // 編集画面終了時に自画面の再検索を行う
                search();
            }
        });
        // 新しいウインドウを表示
        newStage.show();
    }
    
    
    /**
     * RadioButtonCell用ラジオボタングループ
     */
    final ToggleGroup group = new ToggleGroup();
    /**
     * RadioButton型のTableCell
     */
    class RadioButtonCell extends TableCell<Customer, Boolean> {

        private RadioButton radio;

        public RadioButtonCell() {
            createRadioButton();
        }

        /**
         * ラジオボタン生成。
         * <p>
         * ラジオボタングループに登録する
         */
        private void createRadioButton() {
            radio = new RadioButton();
            radio.focusedProperty().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> arg0,
                        Boolean arg1, Boolean arg2) {
                    if (!arg2) {
                        commitEdit(radio.isSelected());
                    }
                }
            });
            radio.setToggleGroup(group);
        }

        @Override
        public void commitEdit(Boolean t) {
            super.commitEdit(t);
            final ObservableList<Customer> items = getTableView().getItems();
            for (int i = 0; i < items.size(); i++) {
                Customer customer = items.get(i);
                if (i == getIndex()) {
                    customer.setSelected(t);
                } else {
                    customer.setSelected(Boolean.FALSE);
                }
            }
        }

        @Override
        public void updateItem(Boolean item, boolean empty) {
            super.updateItem(item, empty);

            // データが存在する行のみラジオボタン表示
            // 引数のemptyは初期表示時全てfalseなのでこんな方法を採択
            final ObservableList<Customer> items = getTableView().getItems();
            if (items != null) {
                if (getIndex() < items.size()) {
                    setGraphic(radio);
                }
            }
        }
    }
}

Emacs + Ruby のつづき

http://www.bookshelf.jp/soft/meadow.html を参考にMeadowいれた。
Cygwinもいれた。

> Meadow を起動し, M-! which find と入力してください.

ほぅほぅ。
M ハイフン ビックリ・・・と入力してもなにも起こらない。

Google先生ー!!

> M: Meta (M-/ は Alt を押しながら / または ESC を押してから /)
Emacs界の隠語(?)らしい。

そうならそうと言ってよぅ。