2010-12-08 9 views
4

私はGroupLayoutを使っていくつかの奇妙な動作を観察しています。 JFrameの内部に含まれているJTextAreaを取得しています。JTextAreaはJFrameのサイズ変更と他のコンポーネントのプッシュを行うJScrollPaneの内部に含まれています。奇妙なことに、JTextAreaの上または下に何もないようにレイアウトを並べ替えると(ギャップもなく)、うまく動作します。それは、テキスト領域がコンテナにどれくらいのスペースがあるかを尋ねているかのように、他のコンポーネントにかかわらず、コンテナの100%をとっているかのようです。もう1つの奇妙なことは、コンテナ内のJTextArea(JScrollPaneではなく)のサイズと他のコンポーネントの高さがShort.MAX_VALUEに達した場合にのみ発生するように見えるということです。JTextAreaがGroupLayoutのフレームをオーバーフローさせるのはなぜですか?

スクロールペインの垂直グループの最大サイズ(レイアウトにコンポーネントを追加するとき)をShort.MAX_VALUEより小さい値に指定すると、問題が解決されたようです(ただし、 Short.MAX_VALUEは、の他のコンポーネントの高さよりも大きいです)。例えば私は小さな正の値にし、代わりにGroupLayout.PREFERRED_SIZEまたはGroupLayout.DEFAULT_SIZEの推奨サイズを設定した場合

.addComponent(textArea, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE - 500)

また、また、この動作は離れて行くように思われます。例えば

.addComponent(textArea, 0, 1, Short.MAX_VALUE)

GroupLayout上のJavaチュートリアルは、このことについては何も言及し、あらゆる場所にShort.MAX_VALUEを使用する傾向があるように思えません。私はグーグルで答えを見つけようとしましたが、この問題を検索用語で説明することは非常に困難でした。

バグが見つかりましたか、GroupLayoutを理解できませんでしたか?後者は確かにそうであるようです。

この例では、単純なテキスト領域が作成されます。下のボタンを押してテキストを入力します(JScrollPane内のJTextAreaのサイズを変更します)。テキスト領域の内側をクリックして、行を追加または削除することができます。余分な行を追加した後、再描画ボタンをクリックするか、フレームのサイズを変更して、奇妙な動作を確認します。

public class GroupLayoutTest { 
    public GroupLayoutTest() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       final JFrame frame = new JFrame("GroupLayout test"); 
       Container panel = frame.getContentPane(); 

       GroupLayout layout = new GroupLayout(panel); 
       panel.setLayout(layout); 

       JButton addBtn = new JButton("Add Lines"); 
       JButton redrawBtn = new JButton("Redraw"); 

       final JTextArea textArea = new JTextArea(); 
       final JScrollPane textPane = new JScrollPane(textArea); 

       layout.setHorizontalGroup(layout.createParallelGroup() 
         .addComponent(redrawBtn) 
         .addComponent(textPane) 
         .addComponent(addBtn)); 

       layout.setVerticalGroup(layout.createSequentialGroup() 
         .addComponent(redrawBtn) 
         .addComponent(textPane) 
         .addComponent(addBtn)); 

       addBtn.addActionListener(new ActionListener() { 
        int m = 0; 

        @Override 
        public void actionPerformed(ActionEvent e) { 
         for (int i = m; m < i + 2044; ++m) { 
          textArea.append("Line " + m + "\n"); 
         } 

         // redraw the frame 
         frame.validate(); 
        } 
       }); 

       redrawBtn.addActionListener(new ActionListener() { 
        @Override 
        public void actionPerformed(ActionEvent e) { 
         frame.validate(); 
        } 
       }); 

       frame.setPreferredSize(new Dimension(640, 480)); 
       frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     new GroupLayoutTest(); 
    } 
} 
+0

1 - のhttp:// sscce.org/ –

答えて

1

私はGroupLayoutの内部を知らないが、一般的に、あなたは、レイアウトマネージャにで動作するようにいくつかの情報を与えることにtextArea /スクロールコンボの推奨サイズを指定する必要があります。そうでなければ、私は推奨サイズは基本的にテキストエリアに追加されたすべてのテキストのサイズであると考えてい

final JTextArea textArea = new JTextArea(10, 30); 

または

textPane.setPreferredSize(new Dimension(400, 200)); 

:これはどちらか使用して行われます。

+0

あなたは正しいです、あなたの提案は問題を解決するようです。しかし、テキスト領域が非常に大きくならない限り、これは必要ではありません。これらの変更がなければ、適切なサイズが正しいので、テキスト領域が「小さい」限り、すべてが表示されます。これは、これを答えの代わりに回避策のように感じさせます。 – jigawot

+1

@jigawot、回避策ではありません。これは、レイアウトマネージャの仕組みです。テキスト領域の仕組みです。 FlowLayoutを使用してテキスト領域をパネルに追加し、入力を開始して何が起こるかを確認します。テキスト領域のサイズは、継続的に変化するテキストに基づいて変化します。コンポーネントの固定サイズを使用してGUIを設計する必要があります。フレームに設定された優先サイズを使用するべきではありません。 pack()メソッドでサイズを決定させる必要があります。テキスト領域は、要件によって決まるreasonble numberの行と列で定義する必要があります。 BorderLayoutを使用します。 – camickr

+0

あなたは非常に有効なポイントを作っていますが、私は正直に反対しなければなりません。 FlowLayoutを使用してポイントを表示すると、これは私が得意とする主要な例です:FlowLayoutを使用する場合は、好ましいサイズを指定する必要があります。 GroupLayoutを使用すると、Short.MAX_VALUEに近づくまで、望ましいサイズを推測し、素晴らしい仕事をすることができます。この奇妙な振る舞いは私の質問の根源であり、私が探している答えではなく、あなたの返信が回避策であると感じる理由は何ですか。私の質問は「なぜ?」 「修正する方法」ではありません。 – jigawot

2

私はGroupLayoutに慣れていませんが、これは私がドキュメントを見て考えているところです。うまくいけばそれは役に立ちます。私の答えは長くなりましたので、上に要約します:

なぜこれが起こりますか? 3つのものの組み合わせ。

  1. GroupLayoutは、コンポーネントの推奨サイズを表します。 (あなたのコメントで判断して、それを選んだ理由です)。
  2. あなたの垂直グループは連続しています。 1つのコンポーネントを一度にレイアウトします。好みのサイズにするか、余裕があれば大きくします。
  3. JScrollPaneには無制限の優先サイズがあります。JTextAreaの好ましいサイズがどんなものになっても、フレームの優先サイズがフレームのサイズより大きくなると、コンポーネントの下にコンポーネントの余地が残っていません。

好ましいサイズを考慮したレイアウトマネージャと非常に大きなサイズのコンポーネントを組み合わせると、通常は常にこの問題が発生します。私は広範囲にテストしていませんが、FormLayoutでもそれが起こっていることがわかります(あなたが推奨サイズを使用するように言うならば)。

説明/思考プロセスで

長い試み:

テキストエリアがどのくらいのスペース 容器の中に、そして、それの100%を、取っている コンテナを求めているかのようにそれはある かかわらず、他のコンポーネント。

テキストエリアには、それは得ることができますどのように大きなコンテナを求めていない - それは反対だ - あることを望んでどのように大きなコンテナを語っています。この場合、textAreaはスクロールペインに直接含まれています。テキスト領域の推奨サイズは、テキスト領域内のテキストのサイズとともに大きくなります。スクロールペインの優先サイズは、スクロールペインに優先サイズを設定しないかぎり、テキストエリアの推奨サイズとともに拡大します。そこから、レイアウトマネージャは物事をどのようにレイアウトするかを決めます。

この場合、垂直レイアウトにはSequentialGroupを持つGroupLayoutを使用しています。これは、最小/プレフィックス/最大サイズに基づいてコンポーネントを順番にレイアウトします。あなたがグループ内の最後の項目としてtextPaneの位置を変更した場合、それは他のコンポーネントからスペースを奪うつもりはありません...私の推測では、非常に大きなサイズの場合、GroupLayoutはすべてのコンポーネントが表示されるかどうか気にしません最後のコンポーネントの後に余分なスペースはなく、コンテナが拡大されるまで表示されません。小さなサイズの場合、ユーザーはフレームのサイズを調整できますが、例のような大きなサイズの場合は実現できません。

巨大なスクロールペインの組み合わせのように見えますが、GroupLayoutはいつ停止するのかわからないため、スクロールペインバーバーの下端が切れてしまいます。 @camickrのように、JScrollPaneで合理的な推奨サイズを設定するだけで、これをすべて回避することができます。

他の奇妙なことは、ときにのみJTextAreaに(ない JScrollPaneに)サイズプラスShort.MAX_VALUEに達する コンテナ内の他の コンポーネントの高さを発生する を表示されていることです。

それぞれのコンポーネントのサイズをログに記録すると、JScrollPaneの推奨サイズを指定しない限り、常にtextAreaよりも好ましいサイズになるため、上記の陳述が正しいと思う。スクロールペインとコンテナ内の他のコンポーネントのサイズは、引き続きShort.MAX_VALUEを超え、GroupLayoutの問題を引き起こすように見えます。

JScrollPaneのポイントは、大きな(または潜在的に大きい)優先サイズのコンポーネントを、含まれている小さな領域(必要に応じてスクロールバー)に格納することです。それで、スクロールペインをいつも好みのサイズよりも大きなサイズにすることができますが、それはスクロールペインをどれだけ大きくすべきかを伝えることから始まります。実際に、望ましいサイズを設定すると、スクロールバーが必要なときにJScrollPaneに効果的に通知されます。たとえば、スクロールペインの適切なサイズが400,300の場合、含まれるコンポーネントの推奨幅が400(またはスクロールペインのサイズがコンテナ内にあり、それが望ましいサイズより大きくなるようになっている場合)を超えるたびに、水平スクロールバーを表示します。同様に、高さについても同様です。さもなければ、それはあなたが持っているもののサイズに常に成長し、スクロールバーやポイントを削除したり、場合によっては他のコンポーネントの表示を妨げたりすることはありません。

GroupLayoutのドキュメントは、一般的には他のレイアウトビルダーツールで使用されていますが、通常は開発者によっては使用されません。私は、適切に動作するために特別な最大値を使用することを日常的に必要とするものとは異なるレイアウトを使用することを検討します。私の個人的なお気に入りはFormLayout、BSDライセンスの第三者レイアウトマネージャーです。通常のコンポーネントの固定サイズを指定する必要はありませんが、スクロールペインの場合は、推奨サイズを考慮したレイアウトで優先サイズを指定する必要があります。

DPIを尊重し、適切な場所で成長し、国際化(テキストの長さが非常に異なる可能性があります)でうまく動作するようにレイアウトをしたいので、すべての固定サイズを指定する必要はありません。私は、ほとんどのレイアウトで、スクロールペインに固定の優先サイズを設定することは悪いことではないと思います。ボタン、テキストフィールド、または明らかに好ましいサイズを持つ他のコンポーネントをあまり多くはないようにします。ここで

は(それもビルダーを持っているが、この場合には、私は簡単に列にまたがるセルの制約を使用しています)、それはFormLayoutを統合にどのように見えるかです:SSCCEため

FormLayout layout = new FormLayout(
     "pref,fill:pref:grow", // cols 
     "pref,3dlu,fill:pref:grow,3dlu,pref" // rows 
); 

JPanel panel = new JPanel(layout); 

CellConstraints cc = new CellConstraints(); 

panel.add(redrawBtn, cc.xy(1, 1)); 
panel.add(textPane, cc.xyw(1, 3, 2)); // span 2 columns 
panel.add(addBtn, cc.xy(1, 5)); 

frame.setContentPane(panel); 
+0

まず、あなたの詳細な説明に感謝します。私は以前FormLayoutを見ていないし、間違いなくそれを調べるだろう。私は、スクロールペインの推奨サイズに関するあなたの発言に従っているかどうかはわかりません。私がサイズを記録したとき、スクロールペインの好ましいサイズは、テキスト領域が非常に大きくなっている間に、フレーム(393px)に収まるサイズであることがわかりました。テキストエリアの推奨サイズが約32700になると、スクロールペインの優先サイズが大きくなり、他のコンポーネントがフレームから外れます。 – jigawot

+0

また、スクロール区画の適切なサイズを明示的に設定した場合(たとえ1pxのような)ばかげた値であっても、GroupLayoutはコンポーネントのサイズを適切に(393pxで)、内部に含まれるテキスト領域が非常に大きくなると、フレームの外側に何も押さずに、393ピクセルで右にとどまります。これは私にとって非常に奇妙なようです。興味深いもの: – jigawot

+0

私の場合は、パネルに「再描画」ボタンを配置し、各コンポーネントの最小、優先、最大サイズを印刷する「情報」ボタンを投げた、または多分Javaのバージョンおよび/またはプラットフォームの違い?私はちょうどあなたの再描画ボタンのアクションコードを置き換えて、他のすべてを残してテストしたところ...そしてスクロールペインの望ましいサイズは明らかに述べたように成長しています。私はJava 1.6.0_21、Windows 7のbtw –

関連する問題