私は今それが次のように行うことができることを発見しました:
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()イベントを聞いていましたが、最初の描画には遅すぎます。