3

があり、JPopupMenuそれに応じて動的に内側のサイズを変更したいinner components' size。私の SSCCE では、この問題について説明しました。

SSCCE:

public class PopupTest2 {
    public static void main(String[] a) {
        final JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createLineBorder(Color.RED));

        final JPopupMenu menu = new JPopupMenu();

        // critical step
        JPanel itemPanel = new JPanel();
        itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));

        final JMenuItem[] items = new JMenuItem[10];
        for (int i = 0; i < 10; i++) {
            JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
            itemPanel.add(item);
            items[i] = item;
        }

        menu.add(itemPanel);

        JToggleButton button = new JToggleButton("Press me");
        button.addActionListener(new ActionListener() {
            boolean pressed = false;
            @Override
            public void actionPerformed(ActionEvent e) {
                pressed = !pressed;
                if (pressed) {
                    for (JMenuItem item : items) {
                        item.setText(item.getText()+" changed");
                    }
                } else {
                    for (JMenuItem item : items) {
                        item.setText(item.getText().substring(0, item.getText().length() - 8));
                    }
                }
            }
        });

        panel.add(button, BorderLayout.NORTH);

        panel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
                }
            }
        });
        frame.setContentPane(panel);
        frame.setUndecorated(true);
        frame.setBackground(new Color(50, 50, 50, 200));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.setVisible(true);
            }
        });
    }
}

ステップ 2 再現:

  1. 右クリックしてポップアップ メニューを表示します。
  2. ボタンをクリックしPress meます (ウィンドウの上部にあります)。
  3. 右クリックしてポップアップ メニューを再度表示する (バグ #1 - ポップアップがまだ小さい)
  4. 右クリックしてポップアップ メニューを再度表示します (ポップアップ メニューのサイズは問題ありません)。
  5. Press meボタンをもう一度クリックします。
  6. 右クリックしてポップアップ メニューを表示します。(バグ #2 - ポップアップがまだ大きい)

JPopupMenu表示する前にサイズを強制的に変更するにはどうすればよいですか? にアイテムを直接追加すると機能するのはなぜpopupMenuですか?

4

3 に答える 3

4

これを行う 1 つの方法を次に示します。

public static void main(String[] a) {
    final JFrame frame = new JFrame();
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    final JPanel panel = new JPanel(new BorderLayout());
    panel.setBorder(BorderFactory.createLineBorder(Color.RED));

    final JPopupMenu menu = new JPopupMenu();

    // critical step
    final JPanel itemPanel = new JPanel();
    itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));

    final JMenuItem[] items = new JMenuItem[10];
    for (int i = 0; i < 10; i++) {
        JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
        itemPanel.add(item);
        items[i] = item;
    }

    menu.add(itemPanel);

    JToggleButton button = new JToggleButton("Press me");
    button.addActionListener(new ActionListener() {
        boolean pressed = false;
        @Override
        public void actionPerformed(ActionEvent e) {
            pressed = !pressed;
            if (pressed) {
                for (JMenuItem item : items) {
                    item.setText(item.getText()+" changed");
                    item.setMaximumSize(new Dimension(70, 50));
                    item.setPreferredSize(new Dimension(70, 50));
                    item.setMinimumSize(new Dimension(70, 50));
                    itemPanel.invalidate();
                }
            } else {
                for (JMenuItem item : items) {
                    item.setText(item.getText().substring(0, item.getText().length() - 8));
                    item.setMaximumSize(new Dimension(130, 50));
                    item.setPreferredSize(new Dimension(130, 50));
                    item.setMinimumSize(new Dimension(130, 50));
                    itemPanel.invalidate();
                }
            }
        }
    });

    panel.add(button, BorderLayout.NORTH);

    panel.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON3) {
                menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
            }
        }
    });
    frame.setContentPane(panel);
    frame.setUndecorated(true);
    frame.setBackground(new Color(50, 50, 50, 200));

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            frame.setVisible(true);
        }
    });
}
于 2013-10-22T09:28:30.760 に答える
2

ありがとうございましたが、継続的なデバッグの後に解決策を見つけました。問題は(ポップアップと項目の間)でlayout使用されていました。を直接JPanel呼び出したgetPreferredSize()のを呼び出し、 を呼び出した を呼び出しました。最後のメソッドは、クラスを使用して優先サイズを取得します。このクラスは、サイズに関するデータをstatic オブジェクトに格納します。JPanelmenuItem.getPrefferedSize()BasicMenuItemUI.getPrefferedSize()MainMenuLayoutHelperProperties

デフォルトのJPopupMenuレイアウト -この静的データは、そのメソッドが call で呼び出されるDefaultMenuLayoutたびにクリアされます。同じことを行います-さらに呼び出して、パラメーターを使用してこのメ​​ソッドを呼び出します。preferredLayoutSize()MenuItemLayoutHelper.clearUsedClientProperties(popupMenu)JPanelrevalidate()

public class PopupTest2 {
    public static void main(String[] a) {
        final JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel(new BorderLayout());

        final JPopupMenu menu = new JPopupMenu();

        final JPanel itemPanel = new JPanel();
        itemPanel.setLayout(new BoxLayout(itemPanel, BoxLayout.Y_AXIS));

        final JMenuItem[] items = new JMenuItem[1];
        for (int i = 0; i < 1; i++) {
            JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
            itemPanel.add(item);
            items[i] = item;
        }
        menu.updateUI();

        menu.add(itemPanel);

        JToggleButton button = new JToggleButton("Press me");
        button.addActionListener(new ActionListener() {
            boolean pressed = false;
            @Override
            public void actionPerformed(ActionEvent e) {
                pressed = !pressed;
                if (pressed) {
                    for (JMenuItem item : items) {
                        item.setText(item.getText()+" changed");
                    }
                } else {
                    for (JMenuItem item : items) {
                        item.setText(item.getText().substring(0, item.getText().length() - 8));
                    }
                }
            }
        });

        panel.add(button, BorderLayout.NORTH);

        panel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    MenuItemLayoutHelper.clearUsedClientProperties(itemPanel);
                    itemPanel.revalidate();
                    menu.show(panel, (int) (e.getX() - menu.getPreferredSize().getWidth()), e.getY());
                }
            }
        });
        frame.setContentPane(panel);
        frame.setUndecorated(true);
        frame.setBackground(new Color(50, 50, 50, 200));

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.setVisible(true);
            }
        });
    }
}

PS:読者の皆様、これはコードを記述する最良の方法ではありません。私は本当にそれが必要なのでそうします(私にはそのような要件があります)。JPopupMenu内部なしでビルドできる場合はJPanel、この回答でコードを使用しないでください。

于 2013-10-22T12:28:25.830 に答える
-2

追加する必要があります

menu.updateUI();

メニュー項目を追加した後。

    final JMenuItem[] items = new JMenuItem[10];
    for (int i = 0; i < 10; i++) {
        JMenuItem item = new JMenuItem("Item #"+String.valueOf(i));
        itemPanel.add(item);
        item.setUI(new MyUI());
        items[i] = item;
    }
    menu.updateUI(); <<<<<<--------

    menu.add(itemPanel);
于 2013-10-21T12:22:27.390 に答える