ScrolledCompositeの罠

知っている人にしてみれば「そんなの当たり前やん」と思うことでも、知らないとすごくハマる事例。

Eclipseプラグインを作っていて、ウィザードにスクロールバーをつけたくなった。

スクロールバーを簡単につけるにはorg.eclipse.swt.custom.ScrolledCompositeを使えば良いらしい。サンプルコードはこんな感じらしい。

ScrolledComposite scroll = new ScrolledComposite(tabFolder, SWT.H_SCROLL | SWT.V_SCROLL);
scroll.setLayout(new FillLayout());
scroll.setExpandHorizontal(true);
scroll.setExpandVertical(true);

Composite composite = new Composite(scroll, SWT.NULL);
composite.setLayout(new GridLayout());
scroll.setContent(composite);

...
// compositeに子コントロールをぶらさげる
...

scroll.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));

今回は縦スクロールだけをサポートしたかったので、横に関する記述を削って以下のように実装してみた。

ScrolledComposite scroll = new ScrolledComposite(tabFolder, SWT.V_SCROLL); // ← SWT.H_SCROLLを削除
scroll.setLayout(new FillLayout());
scroll.setExpandVertical(true);
// scroll.setExpandHorizontal(true) を削除

Composite composite = new Composite(scroll, SWT.NULL);
composite.setLayout(new GridLayout());
scroll.setContent(composite);

...
// compositeに子コントロールをぶらさげる
...

scroll.setMinHeight(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); // ←setMinSizeから変更

これで実行してみると、なぜか画面が表示されない。

いろいろコードを変えても駄目。8時間を浪費したあたりでデバッガでコードを追いながらふと
compositeのサイズを確認してみたところ、なんとxが0になっていた。

ひょっとしてと重い、サンプルにあったsetExpandHorizontal(true)を追加してみたところあっけなく表示された。ふぅ。

今回まずかったこと:

  • まずサンプルコードと同じ形で動作を検証しなかった。サンプルコードを見た後「今回は縦スクロールだけだから」と、いきなりサンプルコードを改変した形で実装してしまった。また、途中問題が生じた際にサンプルコードに立ち戻ることなく試行錯誤を繰り返してしまった。
  • メソッドの意味をきちんと確認せずに削ってしまった。 setExpandHorizontal(true)を削る際に、なんとなく横スクロール関連のメソッドだろうと考えてしまい、メソッドの意味を確認せずに削ってしまった。実際はこのメソッドは横スクロール関連のメソッドではなく、「ScrollCompositeの幅がsetMinWidth(int)で指定された最小幅よりも大きい時にコンテンツをScrollCompositeと同じ幅にリサイズするかどうかを設定する」というメソッドであった。最小幅のデフォルトは0なのでsetExpandHorizontal(true)としない限りコンテンツの表示幅は0になってしまい、何も表示されないように見えてしまうというわけである。またせめてsetMinSize()を使っていればコンテンツのデフォルトの大きさで表示されたのだが、ここでも不用意にsetMinHeight()に使うメソッドを変更してしまったためコンテンツが見えないようになってしまっていた。

というわけで教訓。
まずはサンプルをそのまま動かしてみよう。その方がサンプルを改変して動かなくなった際に立ち戻りやすいです。最初から動かないと何が悪いのか突き止めるのが大変になってしまいます。

ドキュメントはきちんと読もう。使うメソッドを変えたりなくしたり追加したりする際にはメソッドの説明を読んで、問題がないか確認しましょう。