去年も書いたので今年もまとめておこうと思います.
今年度の仕事
今年度は去年から引き続き同じチームで開発をしていました.
キャラクターのモーションの制御システムや,サウンドシステムをチーム向けにカスタマイズしたりしてました.
規模が小さめなのもあって一人で全キャラクターのリソース管理もしていて,なかなかに大変でした.
サウンドシステムは用語も分からなかったりで色々と大変でした.周りにサウンドシステムを担当した人もいなかったので,自分で調べるしかなかったのですが,それはそれで良い勉強になりました.
今年度多用した言葉
今年度多用した言葉から,今年度を振り返ってみます.
「具体的に何がしたいんですか?」
「こういうことができないか?」と言った質問が来ることがあります.可能かどうかだけ答えても良いのですが,この一言を言っておくだけで色々と違ってきます.聞いてみたら,既にある機能を組み合わせれば出来ることだったり,逆にやらせないためにわざと出来ないようにしていることを迂回するための方法として質問してきていたりします.具体的な話が分かると,取れる対処法も違ってくるので,この言葉は今後も言い続けることになりそうです.
「いつまでに必要ですか?」
余裕のあるときは「あっ,やっておきますよ」で済むんですが,余裕が無くなってくるとそうも言ってられません.早めに必要なのか,そうでも無いのか,スケジュールを告げない人はベテランであってもいます.仕事の優先順位を決める上でも重要な情報なので,今後も使う機会は増えていくと思います.
「もっとシンプルに」
短い期間でしたが,後輩の面倒を見ることになりました.その際,プログラムを見て気付くと何度も言っていたのがこの言葉です.どうも最初からアレやコレやと色々な条件を考えすぎていたので,まずはシンプルな条件で動くコードを書いてみるように言っていました.経験が少ない状態で色々考えても抜けや漏れが出るものです.まずは分かる範囲でシンプルなものを作ってみる.作る過程で色々問題があれば,それを検討して設計に手を加える,ということが大事だと思います.時間が無いならともかく,十分な時間があるのであれば,まずは作ってみるのも重要だと思います.
あと,個人的にシンプルなAPIを上手く組み合わせて何かを実現する方が好きなので,APIはシンプルな方が好きです.
直接話すことは大事
今年度も感じたのは,直接話すことが大事ということです.直接話してみたらすんなり解決した,なんてことは良くあることです.あと,話をしていると色々な用語が出てきて,知らなければそれを調べて,で勉強にもなります.この作業が面倒だ,という雑談から,じゃあそれを楽にできるようにしましょうか,と需要を見つけることもあります.
普段から話していると,色々と相談もしてもらいやすくなるので,そこから自分の知識や経験につながったり,仕事につながったりします.雑談も重要なのです.
特にプログラマ以外との会話が大事です。プログラマにとっては当たり前のことも,プログラマ以外にとっては違ったり,逆もあり得ますから。
相手の分かる言葉で説明する
プログラマ以外の人から良く言われるのが,プログラマの説明は分かりにくい,ということです.難しい言葉や意味の分からない横文字を使おうとするからのようです.
ベテランの人たちが言うのだから,社内でもデザイナが分かるように説明してくれるプログラマは少ないのでしょう.ちゃんと相手の分かる言葉で説明しようとしていると,相手も聞きやすくなって,色々と質問してくれるようになります.質問が来るようになると,それを解決するために色々と知識や技術が身に付いていきます.
ベテランが正しいと思うな
十年以上のベテランでも間違えることはあります.こちらからアプローチしないと動かない人もいます.伝えるべき情報が分かっていない人だっています.ダメな人には言わないと分からないんです.こちらで何とかしてしまうのではなく,ちゃんと言ってあげるのも相手のためだ,と思いました.特にここ最近.
Vim
今年度もVimは大活躍してくれました.Vimが無ければ作業効率は10分の1にまで落ち込んでいたことでしょう.需要があると色々と覚えるもので,今年度はテキストオブジェクトとVimFilerを特に活用しました.
Shougoさんのプラグインはもちろん活躍しています.
Jenkins
CIのツールというよりも,自動ビルドシステムにWebインターフェースを付けるのによさそうだったので使ってみたのですが,他にも色々とできそうです.気付くと社内の他の場所でも使うようになっていて,何故か関連ミーティングに出席することになったり,と付き合いは長くなりそうです.
今年度気に入った本
ノンデザイナーズデザインブック
UIデザイナの方に紹介してもらった本です.情報を上手く伝えるために,文章をどう配置したりするか,といった部分がプログラムを如何に読みやすく書くかに通じる部分がある気がします.また,上手く情報を伝えるための資料を書く際にも役立つ気がします.
ノンデザイナーズデザインブックを読み解く
というスライドも参考になります.
ゲームを動かす技術と発想
この本はゲームを作る上で必要な基本的な説明が載っています.この本が他と違うなと思ったのが,プログラマ向けの本ではないということです.実際,うちでもデザイナーがこの本を読んでたりします.プログラマはつい専門的な用語で説明してしまいがちですが,非プログラマでも分かる言葉で説明する努力は大事だと思います.
Web Audio API
Web Audio APIの本ですが,Web Audio API自体が昔ながらのサウンドシステムのモデルに基づいているらしく,自分が今利用しているサウンドシステムを理解する上でも役立ちそうな感じです.サウンドシステムで利用される用語なども理論や定義などが解説されていて,サウンドシステムを作るのではなく利用する側になった場合に色々と役立ちます.もっと早くにこの本に出会えていたらな,と思います.サウンドデータを扱う本は多々あれど,サウンドシステムについて書かれた本は珍しい気がします.
最後に
今年度は開発の後半に突入したこともあり忙しかったですが,それでもとても楽しい日々を過ごせました.デザイナやサウンドとの関わりから色々な知識や経験を得られ,興味の幅を広げることも出来,本当に良い一年でした.
プログラマ以外と話すことは苦手でしたが,やはり話すことは大事だな,と思った一年でもあったので,今後も「話すこと」をしっかりとしていこうと思います.
来年度は社会人3年目として新人の面倒を見ることもあり,「話すこと」はますます重要になりそうです.
ゲームプログラマとしてのまとめなのに,ゲームプログラミングに関する話がほとんど無いなぁ,と思わないでもないですが,実際仕事をしていてゲームプログラミングが特殊なことをしているわけでもないので,よっぽど特殊な部分を担当しない限りは,仕事の仕方とかについて思うことの方が増えますね.
算譜記録帳
プログラミングに関して調べたり思いついたりしたことを適当にメモっておくだけのブログ.
2013年3月31日日曜日
2013年3月14日木曜日
clang::Preprocessorで字句解析をするまで
clangを使ってC++のコードについてのメトリクスを取得したりするためのツールが作れないか,と思って手を出してみたものの,まず字句解析するだけでも一苦労だった.とりあえず色々調べてみた結果,まずはプリプロセッサを作るところかららしいので,clangのDoxygenのドキュメントを参考にプリプロセッサオブジェクトを作ってみた.
環境は,Mac Book AirのMountain Lionで.
入力のinput.cはこんな感じ.
Makefileはこんな感じ.結構色々リンクする必要がある.llvm関連については,llvm-configで簡単に設定できる.
出力はこんな感じに.
コードの説明も書いておこうかと思ったけど力尽きた.
気が向いたらそのうち書こう.
環境は,Mac Book AirのMountain Lionで.
// main.cpp #include#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/Token.h" using namespace std; int main(int argc, char * argv[]) { clang::DiagnosticIDs * diagnosticIds = new clang::DiagnosticIDs; clang::DiagnosticOptions * diagnosticOptions = new clang::DiagnosticOptions; clang::IgnoringDiagConsumer * diagnosticConsumer = new clang::IgnoringDiagConsumer; clang::DiagnosticsEngine diagnosticsEngine( diagnosticIds, diagnosticOptions, diagnosticConsumer ); clang::LangOptions langOptions; clang::TargetOptions targetOptions; targetOptions.Triple = LLVM_DEFAULT_TARGET_TRIPLE; clang::TargetInfo * targetInfo = clang::TargetInfo::CreateTargetInfo( diagnosticsEngine, &targetOptions ); clang::FileSystemOptions fileSystemOptions; clang::FileManager fileManager(fileSystemOptions); clang::SourceManager sourceManager( diagnosticsEngine, fileManager ); clang::HeaderSearchOptions * headerSearchOptions = new clang::HeaderSearchOptions; clang::HeaderSearch headerSearch( headerSearchOptions, fileManager, diagnosticsEngine, langOptions, targetInfo ); clang::CompilerInstance compilerInstance; clang::PreprocessorOptions * preprocessorOptions = new clang::PreprocessorOptions; clang::Preprocessor preprocessor( preprocessorOptions, diagnosticsEngine, langOptions, targetInfo, sourceManager, headerSearch, compilerInstance ); clang::FileEntry const * pFileEntry = fileManager.getFile("input.c"); clang::FileID fileID = sourceManager.createMainFileID(pFileEntry); preprocessor.EnterMainSourceFile(); clang::Token token; do { preprocessor.Lex(token); if(diagnosticsEngine.hasErrorOccurred()) break; preprocessor.DumpToken(token); std::cout << std::endl; } while(token.isNot(clang::tok::eof)); return 0; }
入力のinput.cはこんな感じ.
main()
{
}
Makefileはこんな感じ.結構色々リンクする必要がある.llvm関連については,llvm-configで簡単に設定できる.
# Makefile main: main.cpp clang++ `llvm-config --cxxflags --ldflags --libs` $^ -o $@ -lclangBasic -lclangFrontend -lclangAST -lclangLex -lclangSerialization -lclangSema -lclangDriver -lclangEdit -lclangAnalysis -lclangParse
出力はこんな感じに.
identifier 'main'
l_paren '('
r_paren ')'
l_brace '{'
r_brace '}'
eof ''
コードの説明も書いておこうかと思ったけど力尽きた.
気が向いたらそのうち書こう.
2013年3月6日水曜日
コメントを自動挿入せずに改行する方法
Vimでプログラムを書いていて,単行コメントを何行か入れた後で次の行ではコメントにせずにしたい,
と思ったときにどうすれば良いのか,自動挿入をキャンセルする方法が無いのかな,と思ったけれど,
特にそれらしいオプションが見つからなかったので,適当にキーマップしてみた.
Ctrlを押しながら改行すると,適当なインデント分の空白を入れて次の行から開始できる,という風にしてみた.
と思ったときにどうすれば良いのか,自動挿入をキャンセルする方法が無いのかな,と思ったけれど,
特にそれらしいオプションが見つからなかったので,適当にキーマップしてみた.
inoremap:call append('.', repeat(' ', indent('.'))) ji
Ctrlを押しながら改行すると,適当なインデント分の空白を入れて次の行から開始できる,という風にしてみた.
2013年2月6日水曜日
FXMLで2つのスライダーを連動させてみた
昼休みに少しずつコードを書いて実験しています.
今日は2つのスライダーを連動させてみました.
まずは,FXML.Simple.fxmlという名前で次のようなXMLを書きます.
Sceneの中に,VBoxでSliderを2つ組み込み,それぞれにfx:idでIDを振ります.
そして,valueは式の形でsliderBの方の値はsliderAの値を見るようにします.
Javaの方は至ってシンプル.このFXMLをロードして表示するだけ.
これで,上側のスライダーを動かすと,下側のスライダーも動きます.
でも,下側のスライダーを動かしても上は何の反応も示しません.
双方向にするには,sliderAの方にはsliderBの値を見るようにFXMLに追加してやるだけです.
こんなに簡単にプロパティのバインドができるとは・・・$を使った部分が
どこまでできるのか,新しいオブジェクトの生成が出来るのか,とかはこれから
調べて行こうと思います.
今日は2つのスライダーを連動させてみました.
まずは,FXML.Simple.fxmlという名前で次のようなXMLを書きます.
<?xml version = "1.0"?>
<?import javafx.scene.Scene?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Slider?>
<Scene width = "640" height = "480" xmlns:fx="http://javafx.com//fxml">
<VBox>
<Slider fx:id = "sliderA" />
<Slider fx:id = "sliderB" value = "${sliderA.value}" />
</VBox>
</Scene>
Sceneの中に,VBoxでSliderを2つ組み込み,それぞれにfx:idでIDを振ります.
そして,valueは式の形でsliderBの方の値はsliderAの値を見るようにします.
Javaの方は至ってシンプル.このFXMLをロードして表示するだけ.
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Simple extends Application {
public static void main(String [] args){
launch(args);
}
public void start(Stage primaryStage) throws Exception {
Scene scene = FXMLLoader.load(getClass().getResource("Simple.fxml"));
primaryStage.setScene(scene);
primaryStage.show();
}
}
これで,上側のスライダーを動かすと,下側のスライダーも動きます.
でも,下側のスライダーを動かしても上は何の反応も示しません.
双方向にするには,sliderAの方にはsliderBの値を見るようにFXMLに追加してやるだけです.
こんなに簡単にプロパティのバインドができるとは・・・$を使った部分が
どこまでできるのか,新しいオブジェクトの生成が出来るのか,とかはこれから
調べて行こうと思います.
2013年1月27日日曜日
TreeItemを開くときと閉じるときのイベント処理
TreeViewの中のTreeItemが開いたときと閉じたときのイベント処理を書いてみた.
まずは,EventHandlerインターフェースを継承して,イベントハンドラを作る.
開くときのイベントは,TreeItemにbranchExpandedEventというのがあったので,
それかどうかを判定してみる.閉じるときのイベントはbranchCollapsedEventらしい.
これを,前に作ったFileTreeItemのコンストラクタで登録させる.
これで,開いたり閉じたりする度にexpandedやcollapsedが表示される.
ただ,これだと木の奥の方に行くほど何度もexpandedが表示されるので,
イベントを一回処理したら終わりにしてみる.
Eventのconsumeを呼び出すと,その後のイベントが伝わっていくのを抑えられる.
で,抑えてみた結果を実行すると,木が開かなくなった.expandedの方のconsumeを
消すと,今度は開くけど閉じることが出来なくなった.どうもイベントは木の根から
呼び出されていくらしい.イベントの発生源から親に向かって呼び出されていくと思っていた.
イベントのハンドラは根にだけ登録して,getSource()で処理する感じになるのかな.
で,これ書くときに一番引っかかったのがジェネリクスに対応した
staticメソッドを呼び出すときは,クラス名. の後に型名を書くということ.
クラス名に型名を指定していてずっと引っかかっていた.
Javaのジェネリクスちゃんと勉強しないとなぁ.
まずは,EventHandlerインターフェースを継承して,イベントハンドラを作る.
開くときのイベントは,TreeItemにbranchExpandedEventというのがあったので,
それかどうかを判定してみる.閉じるときのイベントはbranchCollapsedEventらしい.
import java.io.File;
import javafx.event.EventHandler;
import javafx.scene.control.TreeItem;
public class FileTreeModificationEventHandler
implements EventHandler<
TreeItem.TreeModificationEvent<File>>
{
public void handle(
TreeItem.TreeModificationEvent<File>
event
)
{
if(event.getEventType() ==
TreeItem.<File>branchExpandedEvent())
{
System.out.println("expanded");
}else if(event.getEventType() ==
TreeItem.<File>branchCollapsedEvent())
{
System.out.println("collapsed");
}
}
}
これを,前に作ったFileTreeItemのコンストラクタで登録させる.
public FileTreeItem(final File f){
super(f);
// 開くときのイベントを登録
addEventHandler(
TreeItem.<File>branchExpandedEvent(),
new FileTreeModificationEventHandler());
// 閉じるときのイベントを登録
addEventHandler(
TreeItem.<File>branchCollapsedEvent(),
new FileTreeModificationEventHandler());
}
これで,開いたり閉じたりする度にexpandedやcollapsedが表示される.
ただ,これだと木の奥の方に行くほど何度もexpandedが表示されるので,
イベントを一回処理したら終わりにしてみる.
public void handle(
TreeItem.TreeModificationEvent<File>
event
)
{
if(event.getEventType() ==
TreeItem.<File>branchExpandedEvent())
{
System.out.println("expanded");
event.consume();
}else if(event.getEventType() ==
TreeItem.<File>branchCollapsedEvent())
{
System.out.println("collapsed");
event.consume();
}
}
Eventのconsumeを呼び出すと,その後のイベントが伝わっていくのを抑えられる.
で,抑えてみた結果を実行すると,木が開かなくなった.expandedの方のconsumeを
消すと,今度は開くけど閉じることが出来なくなった.どうもイベントは木の根から
呼び出されていくらしい.イベントの発生源から親に向かって呼び出されていくと思っていた.
イベントのハンドラは根にだけ登録して,getSource()で処理する感じになるのかな.
で,これ書くときに一番引っかかったのがジェネリクスに対応した
staticメソッドを呼び出すときは,クラス名. の後に型名を書くということ.
クラス名に型名を指定していてずっと引っかかっていた.
Javaのジェネリクスちゃんと勉強しないとなぁ.
2013年1月25日金曜日
JavaFX TreeViewとTreeItem
JavaFXのTreeViewを使ってみた.ファイルツリー的なものを作ろうと思ったら,TreeItemのドキュメントにすでに書いてあった.
で,それを自分なりに整理して書いてみた.
まずは,ファイルツリーの要素を表すクラスを,TreeItem<File>を継承して作る.
根の持つ値をnullにしたのは,TreeViewが当たり前ではあるが根として1つしか要素を持てないため.
MacやLinuxでは/だけがルートなので良いが,Windowsの場合CドライブやDドライブと言った
複数のルートが存在するので,何も値を持たない根を用意し,その下にルートを置くようにしたいから.
表示部分は次のように.
Macでは動作確認したけど,これでWindowsでも上手く各種ドライブが
表示されるかどうかは未確認.
Javaはジェネリクスが出た頃くらいから触っていなかったのでドキュメントを読むのも
一苦労だ・・・.コンパイラに型が間違ってるとか言われまくった.
で,それを自分なりに整理して書いてみた.
まずは,ファイルツリーの要素を表すクラスを,TreeItem<File>を継承して作る.
import java.io.File;
import javafx.collections.ObservableList;
import javafx.collections.FXCollections;
import javafx.scene.control.TreeItem;
// ファイルツリーの根や分岐や葉を表すクラス
// 根は値を持たないものとする
public class FileTreeItem extends TreeItem<File> {
public FileTreeItem(){
this(null);
}
public FileTreeItem(final File file){
// 要素の値を設定
super(file);
}
// 木の要素が葉かどうか(末端かどうか)を返す
// 要素が持つ値は根の場合はnullで,
// それ以外では通常のFileオブジェクトになる
@Override
public boolean isLeaf(){
File file = getValue();
return file != null && file.isFile();
}
@Override
public ObservableList<TreeItem<File>> getChildren(){
// 既に一度子要素を作っている場合はそのキャッシュを利用する
ObservableList<TreeItem<File>> children = super.getChildren();
if(!children.isEmpty())
return children;
// 根にファイルを追加する前に通る
File file = getValue();
if(file == null)
return children;
// ファイルの場合
if(!file.isDirectory()){
return FXCollections.emptyObservableList();
}
// ディレクトリの場合
File [] files = file.listFiles();
for(File f : files){
children.add(new FileTreeItem(f));
}
return children;
}
}
根の持つ値をnullにしたのは,TreeViewが当たり前ではあるが根として1つしか要素を持てないため.
MacやLinuxでは/だけがルートなので良いが,Windowsの場合CドライブやDドライブと言った
複数のルートが存在するので,何も値を持たない根を用意し,その下にルートを置くようにしたいから.
表示部分は次のように.
import java.io.File;
import javafx.application.Application;
import javafx.scene.control.TreeView;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Simple extends Application {
public static void main(String [] args){
launch(args);
}
public void start(Stage primaryStage){
// ルートファイルのリストを取得
File [] rootFiles = File.listRoots();
FileTreeItem root = new FileTreeItem();
// 根の要素に各ルートファイルを追加していく
for(File f : rootFiles){
root.getChildren().add(new FileTreeItem(f));
}
// 根の要素を渡してファイルツリーのビューを作成
TreeView treeView = new TreeView(root);
// 無駄なnullのルートは表示しないようにする
treeView.setShowRoot(false);
// TreeViewをシーンに追加して表示する
Scene scene = new Scene(treeView);
primaryStage.setWidth(640);
primaryStage.setHeight(480);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Macでは動作確認したけど,これでWindowsでも上手く各種ドライブが
表示されるかどうかは未確認.
Javaはジェネリクスが出た頃くらいから触っていなかったのでドキュメントを読むのも
一苦労だ・・・.コンパイラに型が間違ってるとか言われまくった.
2013年1月19日土曜日
JavaFX入門
Pythonをやろうと思っていたはずが,JavaFXの勉強を始めていました.
今年も興味がうつろいやすそうです.「うつろわざるもの」になりたい.
JavaFXは,AWTやSwingのようなJavaのGUIフレームワークです.
ちょっとマルチプラットフォームでGUIのあるツールを作りたくなったため,触ってみました.
もっともシンプルなコード(Simple.java)はこんな感じ.
で,これをコンパイルするためにはJavaFXのjarをクラスパスに追加する必要があります.
JavaFXはJava SE 7からは付いてきているようなので,最新版のJava SEを入れれば入っています.
このパスをクラスパスに追加してJavaを実行すれば,ウィンドウが表示されます.
JavaFXでは,WPFのXAMLのようにFXMLというXMLでGUIを記述できます.
さらに,GUIをWYSIWYGエディタで作成できるJavaFX Scene Builderも提供されています.
上の例をFXML(Simple.fxml)で書くとこんな感じ.
上のコードと比較して何となく気付くかもしれませんが,オブジェクト間の関係と
XMLの入れ子関係が関連しているようです.
import文はXMLのProcessing Instructionとして指定するようです.
このFXMLのファイルを先ほどのクラスと同じ階層に置いて,
このファイルを使ってウィンドウを表示するコードは次のような感じに.
FXMLLoaderというのが提供されているわけです.
getClass().getResource("Simple.fxml")はこのクラスのある場所から指定した
リソース(この場合ファイル)のパスを取得してくれるメソッドのようです.
他にもCSSで見た目を変えられる機能もあるようなので,つい色々試したくなってきます.
目的のツールを作ることを忘れてしまいそう.
今年も興味がうつろいやすそうです.「うつろわざるもの」になりたい.
JavaFXは,AWTやSwingのようなJavaのGUIフレームワークです.
ちょっとマルチプラットフォームでGUIのあるツールを作りたくなったため,触ってみました.
もっともシンプルなコード(Simple.java)はこんな感じ.
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Simple extends Application {
public static void main(String [] args){
launch(args);
}
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(new Group()));
// Macでは幅と高さを指定しておかないとウィンドウが見えない
// primaryStage.setWidth(100);
// primaryStage.setHeight(100);
primaryStage.show();
}
}
で,これをコンパイルするためにはJavaFXのjarをクラスパスに追加する必要があります.
JavaFXはJava SE 7からは付いてきているようなので,最新版のJava SEを入れれば入っています.
Windows Javaのインストールフォルダ\jre\lib\jfxrt.jar Mac `/usr/libexec/java_home`/jre/lib/jfxrt.jar
このパスをクラスパスに追加してJavaを実行すれば,ウィンドウが表示されます.
JavaFXでは,WPFのXAMLのようにFXMLというXMLでGUIを記述できます.
さらに,GUIをWYSIWYGエディタで作成できるJavaFX Scene Builderも提供されています.
上の例をFXML(Simple.fxml)で書くとこんな感じ.
<?xml version = "1.0"?> <?import javafx.scene.Scene?> <?import javafx.scene.Group?> <Scene width = "100" height = "100"> <Group /> </Scene>
上のコードと比較して何となく気付くかもしれませんが,オブジェクト間の関係と
XMLの入れ子関係が関連しているようです.
import文はXMLのProcessing Instructionとして指定するようです.
このFXMLのファイルを先ほどのクラスと同じ階層に置いて,
このファイルを使ってウィンドウを表示するコードは次のような感じに.
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Simple extends Application {
public static void main(String [] args){
launch(args);
}
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(
(Scene)FXMLoader.load(
getClass().getResource("Simple.fxml")));
// Macでは幅と高さを指定しておかないとウィンドウが見えない
// primaryStage.setWidth(100);
// primaryStage.setHeight(100);
primaryStage.show();
}
}
FXMLLoaderというのが提供されているわけです.
getClass().getResource("Simple.fxml")はこのクラスのある場所から指定した
リソース(この場合ファイル)のパスを取得してくれるメソッドのようです.
他にもCSSで見た目を変えられる機能もあるようなので,つい色々試したくなってきます.
目的のツールを作ることを忘れてしまいそう.
登録:
投稿 (Atom)