4 JavaFXの機能を使用したSwingアプリケーションの強化
この章では、Swingの表とJavaFXの棒グラフを1つのアプリケーション内で組み合せる方法について学習します。
この章では、Swingアプリケーションを開始点として使用し、JavaFXの機能を追加することによって、このSwingアプリケーションを強化する方法の例を提供します。
サンプルSwingアプリケーション
実際の多くのプロジェクトでは、表を扱うSwingアプリケーションが使用されています。 既存のコードをそのまま使用し、さらにJavaFX APIを活用できます。 たとえば、JavaFXの棒グラフを追加して、表データをカラフルに表示できます。 この章では、Swingの表とJavaFXの棒グラフを処理するSwingInteropサンプルを提供します。 表のセル内のデータを変更すると、棒グラフがすぐに更新されます。
開始点となるのは、図4-1に示す、Swingの表のみを含むサンプル・アプリケーションです。
このアプリケーションは、次の2つのクラスで構成されています。
SampleTableModelクラスは、AbstractTableModelクラスから継承されたクラスであり、表を定義します。
SwingInteropクラスは、JAppletクラスから継承するクラスであり、アプリケーションの基本クラスです。 そのmainメソッドは、イベント・ディスパッチ・スレッド(EDT)上でrunメソッドをコールして、グラフィカル・ユーザー・インタフェース(GUI)を作成します。 runメソッドはJFrameオブジェクトとJAppletオブジェクトを作成し、SwingInteropクラスのインスタンスを使用して、JAppletオブジェクトを初期化します。 その後、initメソッドをコールすることによって、表を作成し、その表をアプレットのコンテンツ・ペインに追加します。
前述のリンクをクリックすると、両方のクラスの実装を確認できます。
JavaFXの棒グラフの統合
棒グラフのデータを提供するには、新しいクラス変数(bcData)と、表からデータを取得し、そのデータを棒グラフに適した形式で返すメソッドを追加することによって、SampleTableModelクラスを変更します。 例4-1に、getBarChartDataメソッドの実装を示します。
例4-1
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.BarChart;
public class SampleTableModel extends AbstractTableModel {
private static ObservableList<BarChart.Series> bcData;
public ObservableList<BarChart.Series> getBarChartData() {
if (bcData == null) {
bcData = FXCollections.<BarChart.Series>observableArrayList();
for (int row = 0; row < getRowCount(); row++) {
ObservableList<BarChart.Data> series =
FXCollections.<BarChart.Data>observableArrayList();
for (int column = 0; column < getColumnCount(); column++) {
series.add(new BarChart.Data(getColumnName(column),
getValueAt(row, column)));
}
bcData.add(new BarChart.Series(series));
}
}
return bcData;
}
//rest of the SampleTableModel class code
}
SwingInteropクラスは、JApplet.initメソッドをオーバーライドして、アプリケーションのコンテンツ・ペインを作成します。 initメソッドを変更して、JavaFXの棒グラフを保持するためのJFXPanelオブジェクトと、JavaFXのグラフと表の両方を保持するためのJSplitPaneオブジェクトを作成します。 例4-2に、initメソッドに加える必要がある変更を太字で示します。
例4-2
@Override
public void init() {
tableModel = new SampleTableModel();
// create javafx panel for charts
chartFxPanel = new JFXPanel();
chartFxPanel.setPreferredSize(new Dimension(PANEL_WIDTH_INT, PANEL_HEIGHT_INT));
//create JTable
JTable table = new JTable(tableModel);
table.setAutoCreateRowSorter(true);
table.setGridColor(Color.DARK_GRAY);
SwingInterop.DecimalFormatRenderer renderer =
new SwingInterop.DecimalFormatRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);
for (int i = 0; i < table.getColumnCount(); i++) {
table.getColumnModel().getColumn(i).setCellRenderer(renderer);
}
JScrollPane tablePanel = new JScrollPane(table);
tablePanel.setPreferredSize(new Dimension(PANEL_WIDTH_INT,
TABLE_PANEL_HEIGHT_INT));
JPanel chartTablePanel = new JPanel();
chartTablePanel.setLayout(new BorderLayout());
//Create split pane that holds both the bar chart and table
JSplitPane jsplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
jsplitPane.setTopComponent(chartTablePanel);
jsplitPane.setBottomComponent(tablePanel);
jsplitPane.setDividerLocation(410);
chartTablePanel.add(chartFxPanel, BorderLayout.CENTER);
//Add the split pane to the content pane of the application
add(jsplitPane, BorderLayout.CENTER);
}
構文エラーをなくすには、例4-3に示すように、import文とchartFxPanelクラス変数の定義を、SwingInteropクラスに追加します。
例4-3
import javafx.embed.swing.JFXPanel;
import javax.swing.*;
public class SwingInterop extends JApplet {
private static JFXPanel chartFxPanel;
// rest of the SwingInterop class code here
}
JavaFXデータをレンダリングするために、SwingアプリケーションのUIを準備しました。 次のステップでは、JavaFXシーンを作成します。 JavaFXシーンは、JavaFXアプリケーション・スレッド上で作成する必要があるため、例4-4に示すように、コードをRunnableオブジェクト内にラップします。 このコードをinitメソッドの末尾に追加します。
例4-5に示すimport文をSwingInteropクラスに追加します。
例4-6に示すように、SwingInteropクラスのcreateSceneメソッドを実装します。 import文を追加し、インスタンス変数chartを定義します。
例4-6
import javafx.scene.Scene;
import javafx.scene.chart.Chart;
private void createScene() {
chart = createBarChart();
chartFxPanel.setScene(new Scene(chart));
}
createBarChartメソッドは、グラフ図を作成し、変更リスナーを表に追加します。 JavaFXデータのすべての変更は、JavaFXスレッド上で発生する必要があります。 このため、JavaFXのグラフを更新するイベント・ハンドラのコードをRunnableオブジェクト内にラップし、Platform.runLaterメソッドに渡します。 例4-7に、createBarChartメソッドの実装を示します。
例4-7
private BarChart createBarChart() {
CategoryAxis xAxis = new CategoryAxis();
xAxis.setCategories(FXCollections.<String>observableArrayList(tableModel.
getColumnNames()));
xAxis.setLabel("Year");
double tickUnit = tableModel.getTickUnit();
NumberAxis yAxis = new NumberAxis();
yAxis.setTickUnit(tickUnit);
yAxis.setLabel("Units Sold");
final BarChart chart = new BarChart(xAxis, yAxis, tableModel.getBarChartData());
tableModel.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
final int row = e.getFirstRow();
final int column = e.getColumn();
final Object value =
((SampleTableModel) e.getSource()).getValueAt(row, column);
Platform.runLater(new Runnable() {
public void run() {
XYChart.Series<String, Number> s =
(XYChart.Series<String, Number>) chart.getData().get(row);
BarChart.Data data = s.getData().get(column);
data.setYValue(value);
}
});
}
}
});
return chart;
}
例4-8に示すimport文を追加します。
例4-8
import javafx.collections.FXCollections; import javafx.scene.chart.BarChart; import javafx.scene.chart.CategoryAxis; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener;
フレームのタイトルを「Swing JTable and Bar Chart」に変更し、SwingInteropアプリケーションを実行します。
図4-2に、アプリケーションのウィンドウを示します。



