0

1 つの直接の子を持つ AWT コンテナーがあり、新しい子をインデックス 0 に追加し、それを表示して、親フレームを検証し、再描画します。(子は Panel を拡張するクラスですが、それは関連していないようです。) すべて問題なく、Container には予想どおり 2 つの直接の子が含まれています。

次に、子を非表示にして子から呼び出すことで子を却下しContainer.remove(this)、続いてコンテナーを検証して再描画します。1.7 より前の以前のすべての JRE では、これは正常に機能し、元の子はコンテナーに残されます。ただし、1.7 ではremove(this)元の子も削除されます。つまり、コンテナが空になります。呼び出しContainer.remove(0)ても同じ効果があります。これを修正する方法はありますか?恐ろしい JVM バグのようです。

すなわち - 開始時: コンテナには子 [A] が含まれています。- B の追加後、コンテナには子 [B,A] が含まれます。- remove(this) または remove(0) を呼び出した後、コンテナーには何も含まれていません: []。

remove()の前に元の子を取得してから元add()に戻すことはできますが、これは必然的に大幅な再描画と許容できないパフォーマンスを引き起こします。

4

2 に答える 2

2

この問題をシミュレートすることはできません。

私の側ではWin7、JDK7_04

ここに画像の説明を入力

ここに画像の説明を入力

ここに画像の説明を入力

プリントアウト

run:
 Components Count after Adds :2
 Components Count after Adds :3
 Components Count after Adds :4
 Components Count after Adds :5
 Components Count after Adds :6
 Components Count after Adds :7
 Components Count after Removes :6
 Components Count after Removes :5
 Components Count after Removes :4
 Components Count after Removes :3
 Components Count after Removes :2
 Components Count after Removes :1
BUILD SUCCESSFUL (total time: 2 minutes 14 seconds)

コードから

import java.awt.*;
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 Container 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 Container();
        panel.setLayout(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() {

            @Override
            public void run() {
                AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
            }
        });
    }
}
于 2012-06-27T18:58:38.070 に答える
0

この例外は、コンポーネントが削除されたときにイベントがトリガーされ、このイベント処理メソッドで引き続きコンポーネントを参照するために発生する可能性があります。たとえば、コードのどこか (actionPeformed() 以外) で最後のコンポーネントを削除すると、イベント actionPerformed が発生/実行されます。しかし、多くの場合、actionPerformed() メソッドには、ユーザー アクション (ユーザーがコンポーネントのどこかをクリックした) に反応するコードが含まれています。そのため、最後のコンポーネントが削除されると、actionPerformed() 内のコンポーネントへの参照によって例外が発生します。

これに対する解決策は、コードを actionPerformed() から、たとえば mouseClicked() など、目的に応じて別のイベント ハンドラに移動することです。

于 2013-01-12T15:20:42.743 に答える