web-dev-qa-db-ja.com

Java Swingでset(Preferred | Maximum | Minimum)Sizeメソッドの使用を避けるべきですか?

何度か、次の方法の使用を提案したことで批判されてきました。

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

Swingコンポーネント。表示されているコンポーネント間の比率を定義する場合、それらの使用に代わるものはありません。私はこれを言われました:

レイアウトでは、答えは常に同じです。適切なLayoutManagerを使用します

私はウェブを少し検索しましたが、主題の包括的な分析は見つかりませんでした。だから私は次の質問があります:

  1. これらのメソッドの使用を完全に避けるべきですか?
  2. メソッドは、理由のために定義されています。それで、いつそれらを使うべきですか?どのコンテキストで?どんな目的のために?
  3. これらの方法を使用することのマイナスの影響は何ですか? (画面解像度の異なるシステム間で移植性を追加することしか考えられません)。
  4. LayoutManagerが希望するすべてのレイアウトのニーズを正確に満たすことはできないと思います。レイアウトの小さなバリエーションごとに新しいLayoutManagerを実装する必要は本当にありますか?
  5. 4の答えが「はい」の場合、これはメンテナンスが困難になるLayoutManagerクラスの急増につながりませんか?
  6. コンポーネントの子間の比率を定義する必要がある状況では(たとえば、child1はスペースの10%を使用し、child2 40%、child3 50%を使用する必要があります)、カスタムLayoutManagerを実装せずにそれを達成することは可能ですか?
464
Heisenbug
  1. これらのメソッドの使用を完全に避けるべきですか?

    アプリケーションコードの場合ははい。

  2. メソッドは、理由のために定義されています。それで、いつそれらを使うべきですか?どのコンテキストで?どんな目的のために?

    私にはわかりませんが、個人的にはAPI設計の事故だと思います。子のサイズについて特別な考えを持つ複合コンポーネントによってわずかに強制されます。 「やや」。カスタムLayoutManagerでニーズを実装する必要があったからです。

  3. これらの方法を使用することのマイナスの影響は何ですか? (画面解像度の異なるシステム間で移植性を追加することしか考えられません。)

    いくつかの(不完全で、残念ながら、SwingLabsのJava.netへの移行によりリンクが切断されます)技術的な理由は、たとえば Rules(hehe) または link @bendicottが my answer へのコメントで見つけました。社会的には、コードを維持し、壊れたレイアウトを追跡しなければならない不幸な仲間に大量の仕事を投げかけます。

  4. LayoutManagerが希望するすべてのレイアウトのニーズを正確に満たすことはできないと思います。レイアウトの小さなバリエーションごとに本当に新しいLayoutManagerを実装する必要がありますか?

    はい、「すべてのレイアウトのニーズ」に非常に優れた近似を満たすのに十分強力なLayoutManagersがあります。大きな3つは、JGoodies FormLayout、MigLayout、DesignGridLayoutです。そのため、実際には、単純で高度に特殊化された環境を除いて、LayoutManagerを記述することはめったにありません。

  5. 4の答えが「はい」の場合、これはメンテナンスが困難になるLayoutManagerクラスの急増につながりませんか?

    (4への答えは「いいえ」です。)

  6. コンポーネントの子間の比率を定義する必要がある状況(たとえば、子1はスペースの10%、子2 40%、子3 50%を使用する必要があります)で、カスタムLayoutManagerを実装せずにそれを達成することは可能ですか?

    Big-Threeのどれでも、GridBagでさえ、できません(実際にマスターすることに煩わされることはありません。

233
kleopatra

いくつかのヒューリスティック:

  • here に示すように、独自のコンポーネントの作成で行われる可能性があるように、set[Preferred|Maximum|Minimum]Size()を実際にオーバーライドする場合は、get[Preferred|Maximum|Minimum]Size()を使用しないでください。

  • here 以下に示すように、コンポーネントの慎重にオーバーライドされたgetPreferred|Maximum|Minimum]Sizeに依存できる場合は、set[Preferred|Maximum|Minimum]Size()を使用しないでください。

  • 以下および here に示すように、set[Preferred|Maximum|Minimum]Size()を使用してpost -validate()ジオメトリを導出します。

  • コンポーネントに適切なサイズがない場合、たとえばJDesktopPane、コンテナのサイズを変更する必要がある場合がありますが、そのような選択は任意です。コメントは、意図を明確にするのに役立ちます。

  • これらの comments で説明されているように、派生サイズを取得するために多くのコンポーネントをループする必要がある場合は、代替レイアウトまたはカスタムレイアウトを検討してください。

enter image description here

import Java.awt.Component;
import Java.awt.Dimension;
import Java.awt.EventQueue;
import Java.awt.GridLayout;
import Java.awt.KeyboardFocusManager;
import Java.beans.PropertyChangeEvent;
import Java.beans.PropertyChangeListener;
import Java.util.ArrayList;
import Java.util.List;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @see https://stackoverflow.com/questions/7229226
 * @see https://stackoverflow.com/questions/7228843
 */
public class DesignTest {

    private List<JTextField> list = new ArrayList<JTextField>();
    private JPanel panel = new JPanel();
    private JScrollPane sp = new JScrollPane(panel);

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                DesignTest id = new DesignTest();
                id.create("My Project");
            }
        });
    }

    private void addField(String name) {
        JTextField jtf = new JTextField(16);
        panel.add(new JLabel(name, JLabel.LEFT));
        panel.add(jtf);
        list.add(jtf);
    }

    private void create(String strProjectName) {
        panel.setLayout(new GridLayout(0, 1));
        addField("First Name:");
        addField("Last Name:");
        addField("Address:");
        addField("City:");
        addField("Zip Code:");
        addField("Phone:");
        addField("Email Id:");
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("permanentFocusOwner",
            new FocusDrivenScroller(panel));
        // Show half the fields
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.validate();
        Dimension d = sp.getPreferredSize();
        d.setSize(d.width, d.height / 2);
        sp.setPreferredSize(d);

        JInternalFrame internaFrame = new JInternalFrame();
        internaFrame.add(sp);
        internaFrame.pack();
        internaFrame.setVisible(true);

        JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.add(internaFrame);

        JFrame frmtest = new JFrame();
        frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmtest.add(desktopPane);
        frmtest.pack();
        // User's preference should be read from Java.util.prefs.Preferences
        frmtest.setSize(400, 300);
        frmtest.setLocationRelativeTo(null);
        frmtest.setVisible(true);
        list.get(0).requestFocusInWindow();
    }

    private static class FocusDrivenScroller implements PropertyChangeListener {

        private JComponent parent;

        public FocusDrivenScroller(JComponent parent) {
            this.parent = parent;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Component focused = (Component) evt.getNewValue();
            if (focused != null
                && SwingUtilities.isDescendingFrom(focused, parent)) {
                parent.scrollRectToVisible(focused.getBounds());
            }
        }
    }
}
98
trashgod

これらのメソッドの使用を完全に避けるべきですか?

いいえ、これらのメソッドの呼び出しまたはオーバーライドが許可されていないことを示唆する正式な証拠はありません。実際、オラクルはこれらのメソッドがサイズのヒントを与えるために使用されると言います: http://docs.Oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment

extendingSwingコンポーネント(カスタムコンポーネントインスタンスのメソッドを呼び出すのではなく)の場合、これらはオーバーライドされる(Swingのベストプラクティス)

最も重要なことは、コンポーネントのサイズをどのように指定しても、コンポーネントのコンテナーが、要求されたコンポーネントのサイズを尊重するレイアウトマネージャーを使用していることを確認してください。

メソッドは、理由のために定義されています。それで、いつそれらを使うべきですか?どのコンテキストで?どんな目的のために?

コンポーネントが適切にレイアウトされるように、コンテナのレイアウトマネージャーにカスタマイズされたサイズのヒントを提供する必要がある場合

これらの方法を使用することのマイナスの影響は何ですか? (画面解像度の異なるシステム間で移植性を追加することしか考えられません)。

  • 多くのレイアウトマネージャーは、コンポーネントの要求された最大サイズに注意を払いません。ただし、BoxLayoutおよびSpringLayoutは実行します。さらに、GroupLayoutは、コンポーネントに触れることなく、最小サイズ、推奨サイズ、または最大サイズを明示的に設定する機能を提供します。

  • コンポーネントの正確なサイズを本当に設定する必要があることを確認してください。各Swingコンポーネントには、使用するフォントとルックアンドフィールに応じて、異なる優先サイズがあります。したがって、サイズを設定すると、異なるシステムでさまざまな外観のUIが生成される

  • GridBagLayoutおよびテキストフィールドで問題が発生する場合があります。コンテナのサイズが推奨サイズよりも小さい場合、最小サイズが使用され、テキストフィールドが大幅に縮小する可能性があります。

  • JFrameは、その動作でgetMinimumSize()を呼び出すだけで、オーバーライドされたsetMinimumSize(..)を強制しません

LayoutManagerが希望するすべてのレイアウトのニーズを正確に満たすことはできないと思います。レイアウトの小さなバリエーションごとに本当に新しいLayoutManagerを実装する必要がありますか?

実装することで使用することを意味する場合は、はい。 1つのLayoutMangerがすべてを処理できるわけではありません。各LayoutManagerには長所と短所があるため、それぞれを組み合わせて最終レイアウトを作成できます。

参照:

46
David Kroukamp

ここには多くの良い答えがありますが、私は理由についてもう少し付け加えたいと思いますwhyこれらは通常避けるべきです(質問は重複したトピックで再び出てきました):

いくつかの例外はありますが、これらの方法を使用している場合、特定のルックアンドフィール(およびシステム固有の設定、たとえば好みのデスクトップフォントなど)で見栄えがよくなるようにGUIを微調整している可能性があります。メソッド自体は本質的に悪ではありませんが、それらを使用する典型的な理由はareです。レイアウトでピクセルの位置とサイズの調整を開始するとすぐに、他のプラットフォームでGUIが壊れる(または最低でも見栄えが悪い)リスクがあります。

この例として、アプリケーションのデフォルトのルックアンドフィールを変更してみてください。プラットフォームで使用可能なオプションを使用した場合でも、結果のレンダリングの質が低いことに驚かれるかもしれません。

したがって、すべてのプラットフォームでGUIを機能的で見栄えの良いものにするために(Javaの主な利点の1つはクロスプラットフォームであることを忘れないでください)、レイアウトマネージャーなどに依存する必要があります。コンポーネントのサイズを自動的に調整して、特定の開発環境外で正しくレンダリングされるようにします。

そうは言っても、これらの方法が正当化される状況は確実に想像できます。繰り返しますが、これらは本質的に悪ではありませんが、通常はGUIの潜在的な問題を示すbig赤いフラグです。使用する場合、または使用する場合は合併症の可能性が高いことを必ず確認し、問題に対するルックアンドフィールに依存しない別の解決策があるかどうかを常に試してみてください。メソッドは必要ありません。

ちなみに、標準のレイアウトマネージャに不満を感じている場合は、たとえば JGoodies 'FormLayout または MigLayout 。一部のGUIビルダーには、サードパーティのレイアウトマネージャーの組み込みサポートさえあります。たとえば、EclipseのWindowBuilder GUIエディターは、FormLayoutおよびMigLayoutのサポートとともに出荷されます。

25
Jason C

Java Swingのレイアウトに問題がある場合は、Karsten Lentzsch here によってFormsフリーウェアライブラリの一部として無料で提供されているJGoodies FormLayoutを強くお勧めします。

この非常に人気のあるレイアウトマネージャーは非常に柔軟で、非常に洗練されたJava UIを開発できます。

Karstenのドキュメントは here にあり、Eclipseからはかなり優れたドキュメント here にあります。

19
Tom

これらの方法は、ほとんどの人にはあまり理解されていません。これらのメソッドを絶対に無視しないでください。これらのメソッドを尊重するかどうかは、レイアウトマネージャー次第です。このページには、どのレイアウトマネージャーがこれらのメソッドのどれを尊重するかを示す表があります。

http://thebadprogrammer.com/swing-layout-manager-sizing/

私は8年以上Swingコードを書いてきましたが、JDKに含まれるレイアウトマネージャーは常に私のニーズに応えてきました。レイアウトを実現するために、サードパーティのレイアウトマネージャーは必要ありませんでした。

これらのメソッドを使用する必要があると確信するまで、レイアウトマネージャーにこれらのメソッドのヒントを与えないでください。サイズ設定のヒントを与えずにレイアウトを実行します(つまり、レイアウトマネージャーに任せてください)。その後、必要に応じてわずかな修正を行うことができます。

16
Michael

コンポーネントの子間の比率を定義する必要がある状況(子1はスペースの10%、child2 40%、child3 50%を使用する必要があります)で、カスタムレイアウトマネージャーを実装せずにそれを達成することは可能ですか?

多分GridBagLayoutはあなたのニーズを満たすでしょう。それに加えて、ウェブ上にはたくさんのレイアウトマネージャーがあり、あなたの要件に合ったものがあると思います。

15
Thomas

私はそれが受け入れられた答えとは異なっているのを見ています。

1)これらの方法の使用を完全に避けるべきですか?

絶対に避けてください!コンポーネントのサイズの制約をレイアウトマネージャーに表現するためにあります。レイアウトマネージャーを使用していない場合は、それらの使用を避け、視覚的なレイアウトを自分で管理しようとすることができます。

残念ながら、Swingには妥当なデフォルトの寸法がありません。ただし、コンポーネントのサイズを設定する代わりに、適切なデフォルト値を使用して独自のコンポーネントを降ろすことをお勧めしますOOP。 (その場合、子孫クラスでsetXXXを呼び出します。)または、同じ効果を得るためにgetXXXメソッドをオーバーライドすることもできます。

2)メソッドは、理由のために定義されています。それで、いつそれらを使うべきですか?どのコンテキストで?どんな目的のために?

常に。コンポーネントを作成するとき、そのコンポーネントの使用に応じて、現実的な最小/推奨/最大サイズを設定します。たとえば、英国などの国の記号を入力するためのJTextFieldがある場合、その推奨サイズは2文字(現在のフォントなど)に収まる幅になりますが、それ以上大きくすることはおそらく意味がありません。結局のところ、国の記号は2文字です。逆に、入力するためのJTextFieldがある場合顧客名の場合、20文字のピクセルサイズなどの推奨サイズを使用できますが、レイアウトのサイズが変更されると大きくなる可能性があるため、最大サイズをそれ以上に設定します。同時に、幅0pxのJTextFieldは無意味なので、現実的な最小サイズを設定します(ピクセルサイズは2文字と言います)。

3)これらの方法を使用すると、どのようなマイナスの影響がありますか?

(画面解像度の異なるシステム間で移植性を追加することしか考えられません)。

負の結果はありません。これらは、レイアウトマネージャーのヒントです。

4)LayoutManagerが希望するすべてのレイアウトのニーズを正確に満たすことはできないと思います。

レイアウトの小さなバリエーションごとに新しいLayoutManagerを実装する必要は本当にありますか?

いいえ、間違いありません。通常のアプローチは、水平および垂直レイアウトなどのさまざまな基本レイアウトマネージャーをカスケードすることです。

たとえば、次のレイアウト:

<pre>
+--------------+--------+
| ###JTABLE### | [Add]  | 
| ...data...   |[Remove]|
| ...data...   |        |
| ...data...   |        |
+--------------+--------+
</pre>

2つの部分があります。左と右の部分は水平レイアウトです。右側は、水平レイアウトに追加されたJPanelです。このJPanelは、ボタンを垂直にレイアウトする垂直レイアウトを持っています。

もちろん、これは実際のレイアウトでは扱いにくい場合があります。したがって、深刻なものを開発しようとしている場合は、MigLayoutなどのグリッドベースのレイアウトマネージャーの方がはるかに優れています。

5)4への答えが「はい」である場合、これはメンテナンスが困難になるLayoutManagerクラスの急増につながりませんか?

いいえ、特別なものが必要な場合を除き、レイアウトマネージャーを絶対に開発しないでください。

6)プロポーションを定義する必要がある状況では...

コンポーネントの子間(例えば、child1はスペースの10%、child2 40%、child3 50%を使用する必要があります)、カスタムLayoutManagerを実装せずにそれを達成することは可能ですか?

基本的に、適切なサイズが適切に設定されると、パーセンテージで何もしたくない場合があります。単純に、パーセンテージは無意味なので(たとえば、ウィンドウサイズの10%のJTextFieldを持つことは無意味です-JTextFieldが0px幅になるようにウィンドウを縮小したり、JTextFieldがマルチディスプレイ設定)。

ただし、GUIの大きなビルディングブロック(パネルなど)のサイズを制御するためにパーセンテージを使用する場合があります。

JSplitPaneを使用すると、2辺の比率を事前に設定できます。または、MigLayoutを使用して、パーセンテージ、ピクセル、その他の単位でこのような制約を設定できます。

6
Gee Bee

これらのメソッドの使用を完全に避けるべきですか?それらを「避ける」とは言いません。必要だと思うなら、おそらく何か間違ったことをしていると思います。コンポーネントのサイズはコンテキストで決定されます。たとえば、テキストコンポーネントのサイズは、指定した行と列の数と、選択したフォントの組み合わせによって決まります。ボタンとラベルのサイズは、グラフィックを設定した場合はグラフィックのサイズ、または設定したテキストを表示するために必要なスペースになります。各コンポーネントには自然なサイズがあり、レイアウトマネージャーはそれらを使用して、サイズを指定する必要なくすべてをレイアウトします。主な例外はJScrollPaneで、これには含まれているものとは無関係のサイズがあります。それらのために、私は時々setSize()を呼び出し、JFrame.pack()を呼び出して、そのサイズに初期ウィンドウサイズを決定させます。通常、ウィンドウサイズでJScrollPaneサイズを決定します。ユーザーがウィンドウのサイズを決定します。レイアウトマネージャーの多くは、設定したサイズを無視します。そのため、多くの場合、うまく機能しません。

メソッドには理由が定義されています。それで、いつそれらを使うべきですか?どのコンテキストで? レイアウトマネージャーにヒントを提供するために追加されたと思います。レイアウトマネージャーは新しく、人々は完全に信頼していないため、これらは歴史的な理由で作成された可能性があります。新しいパラダイムの学習に煩わされたくないという理由だけで、レイアウトマネージャーを避けてすべてを手動で配置した開発者を数人知っています。それはひどい考えです。

これらの方法を使用することのマイナスの影響は正確には何ですか? (画面解像度が異なるシステム間で移植性を追加することしか考えられません。)それらは効果がなく、オブジェクトを不自然なサイズに圧縮したり引き伸ばしたりして、悪いレイアウトを作成します。そして、レイアウトは脆弱になります。ウィンドウサイズを変更すると、レイアウトが崩れ、間違った場所に配置されることがあります。

LayoutManagerは、必要なすべてのレイアウトのニーズを正確に満たすことはできないと思います。レイアウトの小さなバリエーションごとに本当に新しいLayoutManagerを実装する必要がありますか?新しいLayoutManagerを「実装」するべきではありません。既存のものをインスタンス化する必要があります。多くの場合、1つのウィンドウで複数のレイアウトマネージャーを使用します。各JPanelには独自のレイアウトマネージャーがあります。保守が難しいため、ネストされたレイアウトを嫌う人もいます。それらを使用するときは、それぞれに独自の作成方法を与えて、それぞれが何をするのかを見やすくします。しかし、レイアウトマネージャーを「実装」することはありません。インスタンス化するだけです。

4への答えが「はい」の場合、これはメンテナンスが難しくなるLayoutManagerクラスの急増につながりませんか?の新しいレイアウトマネージャークラスを実装している場合レイアウトのわずかな違い、あなたはそれらを間違って使用しています。新しいレイアウトマネージャーを実装しているだけであれば、おそらく何か間違ったことをしていることになります。 LayoutManagerクラスを拡張したのは、ズームスライダーをJScrollPaneに追加することだけでした。

コンポーネントの子の間の比率を定義する必要がある状況(たとえば、child1はスペースの10%を使用し、child2 40%、child3 50%を使用する)では、 custom LayoutManager?JSplitPaneには、各コンポーネントが取得する割合を指定する方法があります。仕切りはデフォルトで移動可能ですが、必要に応じてオフにすることができます。私はその機能をあまり使いません。通常、設定されたサイズを占めるコンポーネントがいくつかあり、残りのスペースはスクロールペインによって占有されます。スクロールペインのサイズはウィンドウサイズに合わせて調整されます。 2つのスクロールペインが横に並んでいる場合、それらをJSplitPaneに配置し、ユーザーがウィンドウを拡大および縮小するときに各ペインに割り当てる新しいスペースの割合を指定できます。

0
MiguelMunoz