1

これは重複しているように見えるかもしれませんが、invalidate / validate / revalidate / repaintを試してみてもうまくいかないので、ご容赦ください。私のパネル構造は次のようになります。

JPanel/GridBagLayout (1)
+-- JPanel/BorderLayout
    +-- JPanel/GridBagLayout (2)
    |   +-- JTextField (3)
    |   +-- JComboBox
    +-- JPanel/WhateverLayout
    ...

...など。サブパネル(2)でインセット(右と下)を変更し、トップパネル全体をレイアウトしたいと思います(1)。すべてをレイアウトする簡単な方法はありますか(できればトップパネル(1)から下に向かって)、機能するものはすべて問題ありません。今、私はすべてのレベルで無効化/検証/再検証/再描画の組み合わせを試しましたが、何も機能していないようです(実際には何も変わりません)。ありがとう!

編集:GridBagLayoutコンポーネントが追加されたときにクローンが追加されたことがわかりました。そのGridBagConstraintsため、revalidateや友人を実行してもコードが機能しなかったのは、間違った制約を更新したためです。私はこの問題の解決策を以下で見つけて追加しました。

4

3 に答える 3

2
  • re_layout全体JFrameJDialogei)はそこにありますJFrame#pack()

  • コンテナ内の利用可能な領域を埋めるために(remove/の後add)がありrevalidate()repaint()

  • のどのコンテナを選択する必要がありますComponents hierarchy

pack()&&に関するコード(re)validate()repaint()

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

public class AddComponentsAtRuntime {

    private JFrame f;
    private JPanel panel;
    private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;

    public AddComponentsAtRuntime() {
        JButton b = new JButton();
        b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 10));
        panel = new JPanel(new GridLayout(0, 1));
        panel.add(b);
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "Center");
        f.add(getCheckBoxPanel(), "South");
        f.setLocation(200, 200);
        f.pack();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        checkValidate = new JCheckBox("validate");
        checkValidate.setSelected(false);
        checkReValidate = new JCheckBox("revalidate");
        checkReValidate.setSelected(false);
        checkRepaint = new JCheckBox("repaint");
        checkRepaint.setSelected(false);
        checkPack = new JCheckBox("pack");
        checkPack.setSelected(false);
        JButton addComp = new JButton("Add New One");
        addComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton b = new JButton();
                b.setBackground(Color.red);
                b.setBorder(new LineBorder(Color.black, 2));
                b.setPreferredSize(new Dimension(600, 10));
                panel.add(b);
                makeChange();
                System.out.println(" Components Count after Adds :" + panel.getComponentCount());
            }
        });
        JButton removeComp = new JButton("Remove One");
        removeComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int count = panel.getComponentCount();
                if (count > 0) {
                    panel.remove(0);
                }
                makeChange();
                System.out.println(" Components Count after Removes :" + panel.getComponentCount());
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(checkValidate);
        panel2.add(checkReValidate);
        panel2.add(checkRepaint);
        panel2.add(checkPack);
        panel2.add(addComp);
        panel2.add(removeComp);
        return panel2;
    }

    private void makeChange() {
        if (checkValidate.isSelected()) {
            panel.validate();
        }
        if (checkReValidate.isSelected()) {
            panel.revalidate();
        }
        if (checkRepaint.isSelected()) {
            panel.repaint();
        }
        if (checkPack.isSelected()) {
            f.pack();
        }
    }

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

            public void run() {
                AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
            }
        });
    }
}
于 2012-06-27T11:53:33.090 に答える
2

GridBagLayoutコンポーネントが追加されたときにクローンGridBagConstraintsを作成します(そのため、元のファイルを一度変更してもレイアウトに影響はありませんでした)。そのためGridBagLayout、実際の制約ランタイムを更新できるように拡張しました。以下のコードは、コンポーネントのタイプに応じてレイアウトマージンを設定し、「拡張」されている場合は、2つのモードを切り替えるために使用します。

public class ExpandableGridBagLayout extends GridBagLayout {

    public void setExpand(boolean expanded) {
        for (Map.Entry<Component, GridBagConstraints> entry : comptable.entrySet()) {
            setExpandedMargin(entry.getKey(), entry.getValue(), expanded);
        }
    }

    private void setExpandedMargin(Component component, GridBagConstraints constraints, boolean expanded) {
        constraints.insets.right = 2;
        if (component instanceof JLabel) {
            constraints.insets.top = expanded ? 3 : 0;
            constraints.insets.bottom = expanded ? 3 : 0;
        } else {
            constraints.insets.bottom = expanded ? 8 : 5;
        }
    }
}

それから私がしなければならなかったのは、期待通りに作業を呼び出しpanel.revalidate()てレイアウトすることだけでした。(1)

于 2012-06-27T13:37:26.980 に答える
2

正確なコンテキストについてはまだ完全にはわかりませんが、「答え」から判断すると、コンポーネントの制約をその場で変更しているようです。影響を受けるパーツの再レイアウトをトリガーするには、次のことを行う必要があります。

  • 制約が変更された子/renを無効にします(注:親を無効にするだけで不十分です)。これにより、必要に応じて階層がバブルアップします。
  • 階層の上位にある適切なコンテナを検証します

スニペット:

ExpandableGridBagLayout bag = panel2.getLayout();
bag.setExpand(true);
for(Component child: panel2.getComponents())
    child.invalidate();
panel1.validate();

特定のコンテナの下にあるすべてのものを再帰的に無効にするパブリックAPIはありません(invalidateTreeはパッケージプライベートです)。簡単なハックは、親コンテナのフォントを一時的に切り替えることです(これは内部的にinvalidateTreeにメッセージを送ります)

/**
 * Invalidates the component hierarchy below the given container.<p>
 * 
 * This implementation hacks around package private scope of invalidateTree by 
 * exploiting the implementation detail that the method is internally 
 * used by setFont, so we temporary change the font of the given container to trigger
 * its internal call.<p>
 * 
 * @param parent
 */
protected void invalidateTree(Container parent) {
    Font font = parent.getFont();
    parent.setFont(null); 
    parent.setFont(font);
}

編集

この答えのどの部分が間違っていると正確に言っているのかわからない-明らかに私はそれについての詳細な知識なしではあなたの問題を解決することができなかった;-)

不思議なことに、階層の上位にある再検証が、有効な孫/子の再レイアウトにどのようにつながるのか疑問に思っています。validate/Treeは明らかに有効なコンポーネントで停止します。以下は、遊ぶためのコードスニペットです

  • これは2レベルの階層であり、2つの子を持つ親です。
  • アクションは、足元の姉妹のレイアウトに影響するプロパティを変更し(レイアウトのv / hgapを変更します)、親を再検証します

結果は、親のLayoutManagerに応じてfiによって異なります

  • FlowLayoutでは何も起こりません。
  • BoxLayoutを使用すると、状況に応じて検証される場合があります
    • 水平方向または垂直方向のギャップが変更されたかどう
    • ボックスの方向

有効な子のリレーアウトは、より高いレベルのリレーアウトの副作用である可能性がある(またはそうでない)ように見えます-発生する保証がなく、予測するのは困難です。私が頼りたいものは何もない;-)

final JComponent sister = new JPanel();
final Border subBorder = BorderFactory.createLineBorder(Color.RED);
sister.setBorder(subBorder);
sister.add(new JTextField(20));
sister.add(new JButton("dummy - do nothing"));

JComponent brother = new JPanel();
brother.setBorder(BorderFactory.createLineBorder(Color.GREEN));
brother.add(new JTextField(20));
// vary the parent's LayoutManager
final JComponent parent = Box.createVerticalBox();
// final JComponent parent = Box.createHorizontalBox();
// final JComponent parent = new JPanel();
parent.add(sister);
parent.add(brother);

// action to simulate a change of child constraints 
Action action = new AbstractAction("change sub constraints") {

    @Override
    public void actionPerformed(ActionEvent e) {
        FlowLayout layout = (FlowLayout) sister.getLayout();
        layout.setHgap(layout.getHgap() * 2);
      //  layout.setVgap(layout.getVgap() * 2);
      //  sister.invalidate();
        parent.revalidate();
    }
};
brother.add(new JButton(action));

JFrame frame = new JFrame("play with validation");
frame.add(parent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
于 2012-06-27T14:29:43.570 に答える