読者です 読者をやめる 読者になる 読者になる

コントロール その 1

JavaFX

JavaFX シリーズ目次

Swing では GUI で表示するオブジェクトをコンポーネントと呼びますが、JavaFX ではコントロール (正確には UI Controls) と呼びます。

FlexVB でもコントロールと呼ぶので、違和感はないかもしれません。

どうでもいいですけど、この UI Controls はもともと Caspian というプロジェクトで作られていました。もうほとんど残っていないですが、たまーに caspian という記述が残っていることがあります。

さて、このコントロール、Swing のコンポーネントと同じように使うことができます。

とりあえず、Swing コンポーネントとの対応を見てみましょう。

Swing JavaFX
JApplet ×
JButton Button
JCheckBox CheckBox
JCheckMenuItem CheckMenuItem
JColorChooser ×
JComboBox ChoiceBox
JDesktopPane ×
JDialog ×
JEditorPane HTMLEditor
JFileChooser FileChooser
JFormattedTextEditor ×
JFrame Stage
JInternalFrame ×
JLabel Label
JLayer × (必要なし)
JLayeredPane StackPane
JList ListView
JMenu Menu
JMenuBar MenuBar
JMenuItem MenuItem
JOptionPane ×
JPanel Pane
JPasswordField PasswordField
JPopupMenu ContextMenu
JProgressBar ProgressBar
JRadioButton RadioButton
JRadioButtonMenuItem RadioMenuItem
JRootPane Scene
JScrollPane ScrollPane
JSeparator Separator
JSlider Slider
JSpinner ×
JSplitPane SplitPane
JTabbedPane TabPane
JTable TableView
JTextArea TextArea
JTextField TextField
JTextPane × (HTMLEditor)
JToggleButton ToggleButton
JToolBar ToolBar
JToolTip Tooltip
JTree TreeView
JViewport ×
JWindow Window
× Accordion
× CustomMenu
× Hyperlink
× MenuButton
× ProgressIndicator
× SplitMenuButton
× TitledPane

ほとんどの Swing コンポーネントに対応したコントロールがあるのですが、ダイアログ系がないのがイタイですね。

いちおう、Stage をダイアログの代わりにすることができるのですが...

ちなみに FileChooser はありますが、厳密にいうとコントロールではなく、Stage と同列になっています。

Swing にはないコントロールとして、Accordion や Hyperlink、ProgressIndicator などがあります。

Accordion は Flex などでよく使われる上下に開くタイプのコンテナ (?) です。ProgressIndicator は処理待ちの時に円形にグルグル回るコントロールです。

では、実際に主なコントロールを使ってみましょう。

その前に、以下で使用するコードはすべて次のテンプレートで書いてます。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class Test extends Application {
   
    @Override
    public void start(Stage stage) {
        stage.setTitle("Control Demo");
     
        FlowPane root = new FlowPane();
        root.setHgap(10);
        root.setLayoutX(20); root.setLayoutY(20);
        Scene scene = new Scene(root, 400, 200);
        stage.setScene(scene);

        /*
          ここにコントロールのコードを記入します
         */
        
        stage.show();
    }

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

コメントのところに、コードを書いてみてください。

コントロールの大きさによってステージのサイズも変化させているので、そこら辺は適当にやってくださいww

Label

ラベルは使用頻度では一番多いかもしれないですね。文字列を表示するコントロールです。

javafx.scene.text.Text というクラスもあるのですが、こちらは本当に文字列だけです。それに対し、Label クラスはアイコンも使用することができます。

まずは単純な文字列。

    Label label = new Label("Label");
    root.getChildren().add(label);

ラベルで表示している文字列の取得は getText メソッド、文字列の設定は setText メソッドでできます。

f:id:skrb:20120305214356p:image

では、次にアイコンをつけてみましょう。

Swing ではアイコンは Icon クラスで表していましたが、JavaFX では Node クラスです。なので、何でもありです。

    Label label1 = new Label("Label 1",
                             new Rectangle(2, 2, 6, 6));
    root.getChildren().add(label1);

    Label label2 = new Label("Label 2",
                             new ImageView(new Image("src/bullet.png")));
    root.getChildren().add(label2);

アイコンはコンストラクタの第 2 引数で指定します。後から指定するには、setGraphic メソッドを使用します。ここでは、アイコンとして四角と、イメージをロードして使用しました。

f:id:skrb:20120305214551p:image

Button

使用頻度ではボタンも多いですね。Button クラスは JButton クラスとほとんど使い方は同じです。

まずは、テキストだけのボタンです。

    Button button = new Button("Button");
    button.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            System.out.println("Button is clicked.");
        }            
    });
    root.getChildren().add(button);

ボタンに表示するテキストは setText メソッドでも設定できます。

イベントについては、また別の機会に詳しく書こうと思っていますが、Swing のようにイベントの種類ごとにリスナがあるのではなく、すべて EventHandler クラスで扱います。イベントの種類はジェネリクスで指定します。

これを実行すると、下図のようになります。


f:id:skrb:20120305214954p:image


次にアイコンつきのボタンです。

Button クラスのアイコンも Node クラスです。なので、何でもありです。

    Button button1 = new Button("Button1", 
                                new Rectangle(2, 2, 6, 6));
    root.getChildren().add(button1);

    Button button2 = new Button("Button2", 
                                new ImageView(new Image("src/bullet.png")));
    root.getChildren().add(button2);
        
    Button button3 = new Button("Button3",
                                new RadioButton("RadioButton"));
    root.getChildren().add(button3);

ここでは、ボタンを 3 つ並べています。四角とイメージは Label の時と同じです。最後は、ボタンの中にラジオボタンが入ります。

こんなんでもありなのです。

実行すると、こうなります。

f:id:skrb:20120305215216p:image

なんか不思議な感じですよね。でも、ちゃんと動作します。ラジオボタンもちゃんとチェックできます。

f:id:skrb:20120305215300p:image

TextField

続いて、TextField です。

Swing の JTextField クラスだとコンストラクタにはカラム数を指定しますが、TextField クラスでは setPrefColumnCount メソッドで指定します。

    TextField field = new TextField("TextField");
    field.setPrefColumnCount(20);
    root.getChildren().add(field);

実行してみましょう。

f:id:skrb:20120305232231p:image

TextField に入力された文字列を取得するには、getText メソッドを使用します。

ちなみに、JavaFX はまだフォント周りのバグが結構残っていて、JavaFX 2.0 だと日本語を入力するとカーソルがずれるというバグがあります。

Windows 版の JavaFX 2.1 だと直っているのですが、Linux 版はまだバグったままです。

Linux 版で日本語を入力するとこうなります。

f:id:skrb:20120306002939p:image

Linux 版の品質はまだまだといったところでしょう。

さて、3 つのコントロールができたので、3 つを組み合わせてみましょう。

ボタンをクリックしたら、テキストフィールドに入力した文字列をラベルにセットするというサンプルです。

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ControlsDemo extends Application {
    private TextField field;
    private Label label;
    
    @Override
    public void start(Stage stage) {
        stage.setTitle("Control Demo");
     
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 340, 120);
        stage.setScene(scene);

        HBox hbox = new HBox(10);
        hbox.setAlignment(Pos.CENTER);
        root.getChildren().add(hbox);

        field = new TextField();
        field.setPrefColumnCount(20);
        hbox.getChildren().add(field);

        Button button = new Button("Update");
        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // テキストフィールドの文字列をラベルにセットする
                String text = field.getText();
                label.setText(text);
            }            
        });
        hbox.getChildren().add(button);
        
        label = new Label();
        root.getChildren().add(label);
        
        // ステージの表示
        stage.show();
    }

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

レイアウトの部分はあまり見ないでおいて、コントロールの部分だけ見てください。

ボタンがクリックされたら、TextField.getText メソッドで文字列を取得し、Label.setText でセットしているだけです。

実行すると...

f:id:skrb:20120306004449p:image

テキストフィールドに入力して、ボタンをクリックします。

f:id:skrb:20120306004554p:image

次回はまた違うコントロールを使ってみましょう。