質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

JAVAFXのTableViewにボタンを表示させる方法

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 3,123

shibayun

score 12

こんにちは。現在DBのデータをTableViewに表示させ、そのデータ各項目の詳細画面へと遷移するためのボタンを配置したいと思っています。
DBからデータを取得しTableViewに表示させることはできましたが、セルを編集しボタンを実装する方法が分からず頭をかかえております。

http://krr.blog.shinobi.jp/javafx/javafx%20%E3%82%BB%E3%83%AB%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA
こちらのサイトを見るとコンボボックスやテキストフィールドなどは実装可能なようですが...
実装可能な方法がありましたらどうかご教授願います。

イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

TableCell自体を自作するのはどうでしょうか?

 ボタンを表示するためのクラス

import java.util.function.Consumer;

import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

public class ButtonCellFactory<E> implements Callback<TableColumn<E, ?>, TableCell<E, ?>> {

  private String label;
  private Consumer<E> onClick;

  /**
   * @param label ボタンに表示するテキスト
   * @param onClick ボタンがクリックされたときに呼び出される
   */
  public ButtonCellFactory(String label, Consumer<E> onClick) {
    this.label = label;
    this.onClick = onClick;
  }

  @Override
  public TableCell<E, ?> call(TableColumn<E, ?> param) {
    return new TableCell<E, Object>() {
      @Override
      public void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
          setGraphic(null);
          setText(null);
        } else {
          Button btn = new Button(label);
          btn.setOnAction(event -> {
            E value = getTableView().getItems().get(getIndex());
            onClick.accept(value);
          });
          setGraphic(btn);
          setText(null);
        }
      }
    };
  }
}

 使用例兼デモ

ウィンドウ左側の表のボタンを押すと、右側のテキスト領域に
クリックした行のデータを表示します。

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ButtonTableAp extends Application {
  TextArea console;

  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage stage) {
    stage.setWidth(400);
    stage.setHeight(300);

    // 表の作成
    TableView<Entity> table = new TableView<>();
    table.setItems(FXCollections.observableArrayList(
        new Entity("名前1", "詳細1"), 
        new Entity("名前2", "詳細2"),
        new Entity("名前3", "詳細3"),
        new Entity("名前4", "詳細4")));

    // 1列名: 名前
    TableColumn firstNameCol = new TableColumn("名前");
    firstNameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
    table.getColumns().addAll(firstNameCol);

    // 2列名: ボタン
    TableColumn actionCol = new TableColumn("詳細");
    actionCol.setCellValueFactory(new PropertyValueFactory<>("DUMMY"));
    actionCol.setCellFactory(new ButtonCellFactory<Entity>("ボタン", e -> onTableButtonClick(e)));
    table.getColumns().addAll(actionCol);


    // レイアウト
    console = new TextArea();
    BorderPane pane = new BorderPane();
    pane.setLeft(table);
    pane.setCenter(console);

    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
  }

  /** 表のボタン押下時の処理 */
  private void onTableButtonClick(Entity selected) {
    console.setText("名前:\r\n\t" + selected.getName() + "\r\n" + "詳細:\r\n\t" + selected.getDetails());
  }

  /** 表の行のデータ */
  public static class Entity {
    private final SimpleStringProperty name;
    private final SimpleStringProperty details;

    private Entity(String name, String details) {
      this.name = new SimpleStringProperty(name);
      this.details = new SimpleStringProperty(details);
    }

    public String getName() {
      return name.get();
    }

    public void setName(String nm) {
      name.set(nm);
    }

    public String getDetails() {
      return details.get();
    }

    public void setDetails(String dt) {
      details.set(dt);
    }

  }
}

イメージ説明


 コメントへの追記 @ 1/29

私が試した環境(JRE 1.8.0_151および、JDK 9.0.4)だけかもしれませんが、
表のデータ数(行数)に合わせて、ボタンは自動で追加・削除されます。

上記のサンプルでは、表のデータを4件(26行目で設定)としていますが、
後から、データを追加したり、削除しても問題ありませんでした(全件入れ直しも同様)。
表データを追加・削除するサンプルを記載しましたので、あわせてご確認ください。

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class ButtonTableAp2 extends Application {
  private ObservableList<Entity> tableData;
  private TextArea console;

  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage stage) {
    stage.setWidth(400);
    stage.setHeight(300);

    // 表の作成
    TableView<Entity> table = new TableView<>();
    table.setItems(tableData=FXCollections.observableArrayList(
        new Entity("名前1", "詳細1"), 
        new Entity("名前2", "詳細2"),
        new Entity("名前3", "詳細3"),
        new Entity("名前4", "詳細4")));

    // 1列名: 名前
    TableColumn firstNameCol = new TableColumn("名前");
    firstNameCol.setCellValueFactory(new PropertyValueFactory<>("name"));
    table.getColumns().addAll(firstNameCol);

    // 2列名: ボタン
    TableColumn actionCol = new TableColumn("詳細");
    //actionCol.setCellValueFactory(new PropertyValueFactory<>("DUMMY")); 設定しなくても動く
    actionCol.setCellFactory(new ButtonCellFactory<Entity>("ボタン", e -> onTableButtonClick(e)));
    table.getColumns().addAll(actionCol);

    // 表データを変更するためのボタン
    Button addBtn =new Button("表データ追加");
    Button removeBtn =new Button("表データ削除");
    addBtn.setOnAction(event -> addToTable());
    removeBtn.setOnAction(event -> removeFromTable());

    HBox box=new HBox();
    box.getChildren().addAll(addBtn, removeBtn);


    // レイアウト
    console = new TextArea();
    BorderPane pane = new BorderPane();
    pane.setTop(box);
    pane.setLeft(table);
    pane.setCenter(console);

    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
  }

  private void addToTable(){
    int index=tableData.size()+1;
    tableData.add(new Entity("追加名:"+index, "ボタンで追加されたデータです@"+index));
  }

  private void removeFromTable(){
    if(tableData.size()>0){
      tableData.remove(tableData.size()-1);
    }
  }

  /** 表のボタン押下時の処理 */
  private void onTableButtonClick(Entity selected) {
    console.setText("名前:\r\n\t" + selected.getName() + "\r\n" + "詳細:\r\n\t" + selected.getDetails());
  }

  /** 表の行のデータ */
  public static class Entity {
    private final SimpleStringProperty name;
    private final SimpleStringProperty details;

    private Entity(String name, String details) {
      this.name = new SimpleStringProperty(name);
      this.details = new SimpleStringProperty(details);
    }

    public String getName() {
      return name.get();
    }

    public void setName(String nm) {
      name.set(nm);
    }

    public String getDetails() {
      return details.get();
    }

    public void setDetails(String dt) {
      details.set(dt);
    }
  }
}


追加前
追加後

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/29 14:58

    つまり10件のデータを取得し表示した場合、10件のボタンを画像のように配置したいということです...
    説明が下手ですみません。

    キャンセル

  • 2018/01/31 19:57

    すいません。コメントへの追記を忘れていました。
    掲示したサンプルでは、テーブルの行数を4件固定としていましいますが、
    ボタンの表示は、テーブルの行数に合わせて自動的に追加・削除されます。
    ただし、ボタン押下時のイベントは、共通で1つのメソッド(データ行数が不明なため)となるため、
    押された行のデータを受け取るメソッド(サンプルでは、onTableButtonClick)を用意し、
    そのメソッド内で、行データから行うべき処理(質問者様の場合ですと、
    どの詳細画面を開くか)を判断する必要があります。

    ※ 回答にテーブル行数を後から追加・削除した場合の例を追記しています。ご確認ください。

    キャンセル

  • 2018/02/05 10:19

    ありがとうございます。試してみますm(_ _)m

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる