『
JavaFX UIコントロール(全体像)』に引き続き、UIレイアウトの詳細な使い方を見ていく。今回はプログラムを参照しながら、UIコントロールの表示方法とイベント・ハンドラの利用方法を見る。
■ サンプルコード
以下にUIコントロールを利用するサンプルコードと解説を示す。サンプル中で利用されている要素技術については、以下のリンクにて解説している。
◇サンプルの実行結果
◇サンプルプログラム
package application_fx;
import java.io.File;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Pagination;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TitledPane;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.ToolBar;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.web.HTMLEditor;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class TestUIControl2 extends Application {
public static void main(String[] args)
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// メインスレッドを軌道
launch( args );
}
@Override
public void start(Stage primaryStage) throws Exception
{
// シーングラフを作成
VBox root = new VBox( 2.0 );
// メニューを追加
root.getChildren().add( createMenu() );
// ポップアップメニューを追加
ContextMenu popup = createPopupMenu();
root.addEventHandler( MouseEvent.MOUSE_CLICKED , e -> popup.show( primaryStage , e.getScreenX() , e.getScreenY() ) );
// ツールバーを追加
root.getChildren().add( createToolBar() );
// タブ
root.getChildren().add( createTabPane() );
// 区切り線付ペイン
root.getChildren().add( createSplitPane() );
// ページ区切りコントロール
root.getChildren().add( createPagination() );
// ツリービュー
root.getChildren().add( createTreeView() );
// タイトル付ペイン
root.getChildren().add( createTitledPane() );
// HTMLエディタ
root.getChildren().add( createHTMLEditor() );
// ウェブビュー
root.getChildren().add( createWebView() );
// シーンを作成
Scene scene = new Scene( root , 500 , 700 , Color.web( "9FCC7F" ) );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
/**
* メニューを作成
* @return 作成したメニュー
*/
public Node createMenu()
{
// メニュー
MenuBar menuBar = new MenuBar();
Image icon = new Image( new File( "img/chara_one.png" ).toURI().toString() );
ImageView iconView1 = new ImageView( icon );
iconView1.setFitWidth( 15 );
iconView1.setFitHeight( 15 );
// メニューFileを、一般メニューとして作成
// 各メニューにはイメージを付与することが可能
Menu menu1_1 = new Menu( "File" , iconView1 );
MenuItem menu1_2 = new MenuItem( "New" );
MenuItem menu1_3 = new MenuItem( "Save" );
MenuItem menu1_4 = new SeparatorMenuItem();
MenuItem menu1_5 = new MenuItem( "Close" );
menu1_3.setDisable( true );
menu1_1.getItems().addAll( menu1_2 , menu1_3 , menu1_4 , menu1_5 );
// メニューEditを、チェックメニューで作成
Menu menu2_1 = new Menu( "Edit" );
CheckMenuItem menu2_2 = new CheckMenuItem( "check1" );
CheckMenuItem menu2_3 = new CheckMenuItem( "check2" );
menu2_1.getItems().addAll( menu2_2 , menu2_3 );
// メニューViewModeを、ラジオメニューで作成
Menu menu3_1 = new Menu( "ViewMode" );
RadioMenuItem menu3_2 = new RadioMenuItem( "radio1" );
RadioMenuItem menu3_3 = new RadioMenuItem( "radio2" );
ToggleGroup menu3Group = new ToggleGroup();
menu3_2.setUserData( "radio1が選択されました" );
menu3_3.setUserData( "radio2が選択されました" );
menu3_2.setToggleGroup( menu3Group );
menu3_3.setToggleGroup( menu3Group );
menu3_1.getItems().addAll( menu3_2 , menu3_3 );
// メニューにイベントハンドラを登録
menu1_2.addEventHandler( ActionEvent.ACTION , e -> System.out.println( menu1_2.getText() ) );
menu1_3.addEventHandler( ActionEvent.ACTION , e -> System.out.println( menu1_3.getText() ) );
menu1_5.addEventHandler( ActionEvent.ACTION , e -> System.out.println( menu1_5.getText() ) );
menu2_2.selectedProperty().addListener( ( ov , old , current ) -> System.out.println( "check1:" + current ) );
menu2_3.selectedProperty().addListener( ( ov , old , current ) -> System.out.println( "check2:" + current ) );
menu3Group.selectedToggleProperty().addListener( ( ov , old , current ) -> System.out.println( "radio:" + ( ( menu3Group.getSelectedToggle() == null ) ? "" : menu3Group.getSelectedToggle().getUserData() ) ) );
// メニューを登録
menuBar.getMenus().addAll( menu1_1 , menu2_1 , menu3_1 );
return menuBar;
}
/**
* ポップアップメニューを作成
* @return 作成したメニュー
*/
public ContextMenu createPopupMenu()
{
// メニュー
ContextMenu menu = new ContextMenu();
// メニューFileを、一般メニューとして作成
// 各メニューにはイメージを付与することが可能
Menu menu1_1 = new Menu( "poupp1" );
MenuItem menu1_2 = new MenuItem( "popup1_1" );
MenuItem menu1_3 = new MenuItem( "popup1_2" );
MenuItem menu1_4 = new SeparatorMenuItem();
MenuItem menu1_5 = new MenuItem( "popup1_3" );
menu1_3.setDisable( true );
menu1_1.getItems().addAll( menu1_2 , menu1_3 , menu1_4 , menu1_5 );
menu.getItems().addAll( menu1_1 );
// イベントハンドラはMenuItemに設定
menu1_2.addEventHandler( ActionEvent.ACTION , e -> System.out.println( "popup:" + menu1_2.getText() ) );
return menu;
}
/**
* ツールバーを作成
* @return
*/
public Node createToolBar()
{
// ツールバーを作成
ToolBar toolBar = new ToolBar();
// ツールバーにボタンを登録
Image icon = new Image( new File( "img/chara_one.png" ).toURI().toString() );
ImageView iconView1 = new ImageView( icon );
iconView1.setFitWidth( 15 );
iconView1.setFitHeight( 15 );
Button item1 = new Button( "new" );
Button item2 = new Button( "open" );
Button item3 = new Button( "save" );
Button item4 = new Button( "" , iconView1 );
toolBar.getItems().addAll( item1 , item2 , item3 , item4 );
// イベントハンドラはボタンに設定
item1.addEventHandler( ActionEvent.ACTION , e -> System.out.println( "toolbar : " + item1.getText() ) );
return toolBar;
}
/**
* タブペインを作成する
* @return
*/
public Node createTabPane()
{
// タブペインを作成
TabPane tabPane = new TabPane();
// タブ1を作成
Tab tab1 = new Tab();
tab1.setText("タブ1");
tab1.setContent( new Label("タブ1です") );
// タブ2を作成
Tab tab2 = new Tab();
tab2.setText("タブ2");
tab2.setContent( new Label("タブ2です") );
// タブを登録
tabPane.getTabs().addAll( tab1 , tab2 );
return tabPane;
}
/**
* 区切り線付ペインを作成
* @return
*/
public Node createSplitPane()
{
// 区切り線付ペインを作成
SplitPane splitPane = new SplitPane();
// 内部のペイン1を作成
StackPane stack1 = new StackPane();
Label label1 = new Label("ラベル1です");
stack1.getChildren().add( label1 );
// 内部のペイン2を作成
StackPane stack2 = new StackPane();
Label label2 = new Label("ラベル2です");
stack2.getChildren().add( label2 );
splitPane.getItems().addAll( stack1 , stack2 );
// 区切り線の初期位置を設定
splitPane.setDividerPositions( 0.3f );
return splitPane;
}
/**
* ページ区切りコントロールを作成
* @return
*/
public Node createPagination()
{
// ページ区切りコントロールを作成
Pagination pagination = new Pagination( 12 , 1 );
// ページを作成
for( int i=0 ; i<12 ; i++ )
{
// 各ページは、ページ番号を記述したラベル
pagination.setPageFactory( index -> new Label( "ページ番号=" + index ) );
}
return pagination;
}
/**
* ツリービューを作成
* @return
*/
@SuppressWarnings("unchecked")
public Node createTreeView()
{
// ツリー・ビューの作成
TreeView<String> treeView = new TreeView<>();
TreeItem<String> root = new TreeItem<String>( "ルート" );
root.setExpanded( true );
treeView.setRoot( root );
// ツリー・ビューに項目1を登録
TreeItem<String> treeItem1 = new TreeItem<String>("項目1");
treeItem1.setExpanded( true );
for( int i=0 ; i<3 ; i++ )
{
// 子項目を追加
TreeItem<String> item = new TreeItem<String>( "項目1-" + i );
item.setExpanded( true );
treeItem1.getChildren().addAll( item );
}
// ツリー・ビューに項目2を登録
TreeItem<String> treeItem2 = new TreeItem<String>("項目2");
for( int i=0 ; i<2 ; i++ )
{
// 子項目を追加
TreeItem<String> item = new TreeItem<String>( "項目2-" + i );
treeItem2.getChildren().addAll( item );
}
// ツリー・アイテムの登録
treeView.getRoot().getChildren().addAll( treeItem1 , treeItem2 );
// イベントハンドラの登録
treeView.getSelectionModel().selectedItemProperty().addListener(
( ov , old , current ) ->
System.out.println( "TreeView:" + treeView.getSelectionModel().getSelectedItem() )
);
return treeView;
}
public Node createTitledPane()
{
// アコーディオンの作成
Accordion accordion = new Accordion();
// タイトル付ペインの作成
for( int i=0 ; i<3 ; i++ )
{
// ラベルを追加
String title = "タイトル" + i;
Label label = new Label( "ラベル" + i );
// タイトル付ペインの作成
TitledPane titledPane = new TitledPane( title , label );
// タイトル付ペインの登録
accordion.getPanes().add( titledPane );
}
return accordion;
}
/**
* HTMLエディタを作成
* @return
*/
public Node createHTMLEditor()
{
// ルートを作成
VBox root = new VBox();
// サブシーンを作成
HTMLEditor editor = new HTMLEditor();
SubScene subScene = new SubScene( editor, 500 , 150 );
// ボタンを登録
Button button = new Button("HTML取得");
root.getChildren().addAll( subScene , button );
// イベントを登録
button.addEventHandler( ActionEvent.ACTION , e -> System.out.println( "HTML Editor:" + editor.getHtmlText() ) );
return root;
}
/**
* ウェブ・ビューを作成
* @return
*/
public Node createWebView()
{
// ウェブ・ビューを作成
WebView webView = new WebView();
WebEngine webEngine = webView.getEngine();
// URLからロード
webEngine.load( "http://krr.blog.shinobi.jp/" );
return webView;
}
}
■ 解説
◇ メニュー(102行目~150行目)
メニュー・バーはMenuBarクラス、メニューの分類はMenuクラス、メニュー項目はMenuItemクラスで表される。メニュー・バーを表示するにはMenuBarに対してMenuおよびMenuItemを追加し、シーングラフに追加すればよい。イベント・ハンドラは、各メニュー・クラスに設定する。MenuItemクラスにはには以下のクラスが存在する。また、MenuItemには画像(ImageViewクラス)を設定可能である。
- MenuItem :一般的なメニュー
- CheckMenuItem :チェック・ボタン形式のメニュー
- RadioMenuItem :ラジオ・ボタン形式のメニュー。ToggleGroupが設定可能
- CustomMenuItem :任意のUIコントロールを表示するメニュー
- SeparatorMenuItem :セパレータ
◇ ポップアップ・メニュー(63行目、156行目~175行目)
ポップアップ・メニューはContextMenuクラスで表される。メニュー項目などは通常のメニューと同じクラスが利用できる。ポップアップ・メニューを表示するには、ContextMenu::show関数を呼び出す必要がある。
◇ ツールバー(182行目~201行目)
ツールバーを表示するには、Toolbarクラスをシーングラフに追加すればよい。ツールバー内には、UIコントロールを追加可能である。
◇ タブ(208行目~228行目)
タブを利用するには、TabPaneクラスでタブの表示領域を作成して、そこにTabクラスを追加すればよい。Tab::setText関数でタブの名称を、Tab::setContent関数でタブの中身を設定する。
◇ 区切り線付ペイン(234行目~254行目)
区切り線付ペインを利用するには、SplitPaneクラスで表示領域を作成し、表示するUIコントロールを追加すればよい。区切り線の初期位置はSplitPane::setDividerPositions関数にて、0(左端)~1.0(右端)の値を指定する。
◇ ページ区切りコントロール(260行目~273行目)
ページ区切りコントロールを利用するにはPaginationクラスを総ページ数と初期表示のページ番号指定で作成する。総ページ数を指定したくない場合は定数Pagination.INDETERMINATEを指定する。ページを追加するにはPagination::setPageFactory関数に、ページを作成するロジックを記述したCallBackインターフェースを渡す。サンプルではラムダ式を用いてcall関数をオーバーライドした匿名クラスを作成している。call関数では引数としてページ番号が渡されるので、戻り値に該当ページ番号として表示するUIコントロールを返すように設定する。
◇ ツリー・ビュー(279行目~319行目)
ツリー・ビューはTreeViewクラスで表示領域を設定し、ツリーの枝・葉ノードをTreeItemクラスで表す。TreeItemクラスは子を持つことができ、子を持つ場合は枝ノード、子を持たない場合は葉ノードに該当する。TreeView::getSelectionModel().selectedItemPropertyに対してバインディングを設定することで、選択ノードの変更を検知できる。
◇ タイトル付きペインとアコーディオン(322行目~341行目)
Accordionクラスで表示領域を作成し、各要素はTitlePaneクラスで作成する。TitlePaneクラスはタイトルとして表示する文字列と、表示するUIコントロールを指定して作成する。
◇ HTMLエディタ(347行目~364行目)
HTMLエディタの表示はHTMLEditorクラスをシーングラフに追加するだけでよい。HTMLエディタに入力した内容は、HTMLEditor::getHtmlText関数を用いることでHTML文書の文字列として取得できる。逆にHTML文書の文字列を表示するには、HTMLEditor::setHtmlText関数を利用する。
◇ ウェブ・ビュー(370行目~382行目)
ウェブ・ビューを表示するには、WebViewクラスをシーングラフに追加する。表示するwebページは、WebView::getEngine().load関数でURLを表す文字列を指定する。