2

私はJDialogを持っていますが、特定のサイズを指定したいと思います。

JDialog dialog = new JDialog();
dialog.setSize(800, 600);
dialog.setResizable(false);

次に、コンポーネントを追加します。

JLabel label = new JLabel("Test");
dialog.add(label);

これで、ダイアログを表示して、コンポーネントのサイズを確認できます

dialog.setVisible(true);
System.out.println(label.getSize());

答えは「[width=784、height=562]」になります。明らかに、コンポーネントは、ダイアログウィンドウのクライアント領域/コンテンツペイン全体を埋めるようにサイズ変更されました。それは大丈夫です、そして私が望むように。

質問:setVisible(true)を呼び出す前に、コンポーネントの最終的なサイズを取得するにはどうすればよいですか?

  • コンポーネントを指定されたダイアログのサイズに適合させたいので、getPreferredSize()は希望のサイズにはなりません
  • dialog.pack()も、ダイアログのサイズを不要なコンポーネントの適切なサイズに変更するため、適切ではありません。
  • dialog.validate()はここでは何の役にも立ちません、コンポーネントのサイズはまだ0です
  • dialog.getLayout()。layoutContainer(dialog)もコンポーネントのサイズを設定しません

だから私はここで途方に暮れています。ダイアログを表示する前に、レイアウトマネージャーにすべてのコンポーネントとサブコンポーネントの適切なサイズを計算させ、ダイアログの全体的なサイズに適合させたいと思います。しかし、私は方法がわかりません。

4

2 に答える 2

3

私は今それが次のように行うことができることを発見しました:

JDialog dialog = new JDialog();
JLabel label = new JLabel("Test");
dialog.add(label);

// pack(), setSize(), validate() in this order will
// set sizes on all components as wished
dialog.pack();
dialog.setSize(800, 600);
dialog.validate();

System.out.println(label.getSize());

また、ここでの出力は「[width = 784、height = 562]」ですが、ダイアログはまだ表示されていません。重要な部分は、pack()、setSize(desiredSize)、validate()のこの順序での組み合わせです。pack()は、おそらくダイアログの新しいサイズ(すべてのコンポーネントの推奨サイズ)を決定します。そのため、ここでは後でサイズを設定する必要があり、validate()がコンポーネントのサイズ変更を担当します。おそらく、同じサイズで到着するsetVisible(true)は、内部的に同様のことを行っています。

コンポーネントのサイズを数回変更するのは少しもったいないようですが、pack()がないと、setSize()とvalidate()も効果がありません。

他の回答は、常に希望のサイズが必要であると暗黙的に想定しているため、誤解に基づいていると思いますが、ユーザーがダイアログのサイズを変更したり、ダイアログのサイズが最初から固定されていて達成できない場合などがあります。推奨サイズと一部のコンポーネントは、使用可能なスペースを埋める必要があります。

これがここでのレイアウトの問題でした。ダイアログのグローバルサイズを指定し、使用可能なスペースを埋めるときにコンポーネントのサイズを決定しました。LayoutManagerはこの問題を非常にうまく解決しますが、通常はsetVisible(true)の後でのみです。

もう少しテストしました:

    // new dialog
    JDialog dialog = new JDialog();

    // new label, prints messages if resized or painted
    JLabel label = new JLabel("Test") {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("Component painted.");
        }
    };
    label.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            System.out.println("Resized: " + e.getComponent().getSize());
        }
    });
    dialog.add(label);        
    System.out.println("Size after new JLabel: " + label.getSize());

    // pack dialog - necessary for setSize/validate to work
    dialog.pack();
    System.out.println("Size after pack: " + label.getSize());                

    // set a size and validate changes sizes
    dialog.setSize(800, 600);
    dialog.validate();
    System.out.println("Size after setSize and validate: " + label.getSize());        

    // set visible would have also done the trick
    dialog.setVisible(true);
    System.out.println("Size after setVisible(true): " + label.getSize());

    // and another resizing (no validation neccessary)
    dialog.setSize(300, 200);

    // dispose
    dialog.dispose();

そして出力は

  • 新しいJLabel後のサイズ:java.awt.Dimension [width = 0、height = 0]
  • パック後のサイズ:java.awt.Dimension [width = 116、height = 16]
  • setSize後のサイズと検証:java.awt.Dimension [width = 784、height = 562]
  • setVisible(true)後のサイズ:java.awt.Dimension [width = 784、height = 562]
  • サイズ変更:java.awt.Dimension [width = 284、height = 162]
  • サイズ変更:java.awt.Dimension [width = 284、height = 162]
  • 塗装されたコンポーネント。

私はSwingの内部の仕組みについてもっと学びました:

  • ComponentResizedイベントは、コンポーネントのサイズが変更された(サイズが変更された)場合でも、setVisible(true)の前に発生しません。
  • 同じサイズのComponentResizedイベントは、連続して複数回発生する可能性があります
  • コンポーネントが互いに十分に速く追従する場合、サイズ変更の間にコンポーネントがペイントされない可能性があります
  • いずれの場合も、最初のペイントはsetVisible(true)の後であり、コンポーネントはそれまでに目的のサイズ(推奨サイズまたは他の制約によって定義されたサイズ)になります。
  • 何らかの理由で最初の描画の前にコンポーネントのサイズを知る必要がある場合は、pack()、setSize()、validate()を使用してください。

フレームを最大化してさらにテストしたところ、すべての結果を次のように組み合わせることができます。最初のpainComponent()は常に適切なサイズであり、関連するcomponentResized()イベントは常にその後、場合によっては2回続きます。ただし、LayoutManagerは事前に知っている必要があります。そうしないと、例が正しく描画されません。したがって、背景を単独で描画する場合は、すべてのpaintComponentで適切なサイズを読み取るか、カスタムレイアウトマネージャーを実装するか、サイズ変更されたイベントを待って再描画を呼び出すと、コンポーネントが2回描画されますが、機能するはずです。アプリケーションには、表示するコンポーネントの数がサイズによって異なる場合が含まれます(私の地理マップアプリケーションのように)。


写真を完成させるために、ユーザーがフレーム/ダイアログを最大化またはサイズ変更した場合のフローは次のようになると思います。

  • frame / dialog.setSize()
  • 実際のサイズを使用したLayoutManager.layoutContainer(frame / dialog)
  • レイアウトされたサイズを使用したframe/dialog paint()
  • すべてのコンポーネントなどに対して発生するResized()イベント。

そして、pack()はおそらく最初のステップとしてsetSize(layout.preferredLayoutSize())を呼び出すだけです。

したがって、たとえばコンポーネントを追加または削除する必要があるサイズに応じて、setSize()をオーバーライドし、そこで変更をリッスンすることをお勧めします。私は最初にResized()イベントを聞いていましたが、最初の描画には遅すぎます。

于 2012-10-25T06:29:19.453 に答える
2

トップレベルコンテナは、2つの場合(存在する場合)に独自SizePreferredSize、、を返しますBounds

  • すでに見える

  • 電話の後pack()、あなたの場合dialog.pack();

  • で計算する必要がBordersあり、ToolBarから来ましたNative OS

  • このサイズを取得する必要がありますTop-Level Containers#getContentPane().getWhatever

  • ほとんどのJComponents返品は独自のものPreferredSizeであり、サイズを決定する理由はありませんStandard Layout Manager

于 2012-10-24T09:38:31.927 に答える