本文介绍了可见时更新JPopupMenu高度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中有一个弹出菜单,我想用自定义菜单替换,以使其与外观&其余应用程序的感觉.本质上,不是要在弹出窗口中显示常规菜单项,而是要重用应用程序中其他位置已经存在的组件,该组件使您可以分页"方式而不是子菜单来浏览项的层次结构.因此,如果您单击列表中包含子项的项目,则将显示下一页,将当前列表中的当前项目替换为单击项的子项列表.

I have a popup menu in my application that I want to replace with a customized one so that it matches the look & feel of the rest of the application. Essentially, instead of having the normal menu items in the popup, I want reuse a component that already exist elsewhere in the application that lets you navigate through a hierarchy of items in a "paging" way instead of with sub-menus. So if you click on an item in the list that contains children then the next page will be displayed replacing the current items in the list with a list of the children of the clicked item.

使用分页"组件的优点是,它将与应用程序的其余部分很好地结合在一起(已经在其他非弹出窗口的地方使用过),并且在页面之间导航时具有一些漂亮的动画效果

The advantage of using the "paging" component is that it will fit in well with the rest of the application (it is already used in other places that are not popups) and it has some nice looking animation effects when navigating between pages.

我遇到的问题是,在显示不同页面时分页组件的首选高度会发生变化(列表中项目的数量会发生变化),我希望更新弹出菜单的高度,以使其恰好适合分页组件,但到目前为止,我尝试在可见时更新弹出菜单的高度的尝试都失败了.

The problem I'm having is that the preferred height of the paging component changes when showing different pages (the amount of items in the list change) and I want the popup menu height to update so that it fits the paging component exactly, but so far my attempts to update the height of the popup menu while it is visible have failed.

下面是一个演示该问题的示例应用程序:

Below is an example application that demonstrates the problem:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

public class PopupSizeTestFrame extends JFrame {

    private static final int PREFFERED_WIDTH = 300;
    private static JPanel resizingPanel;
    private static JPopupMenu popupMenu;
    private static PopupSizeTestFrame frame;

    private static void resizePopupMenu() {
        // What should I do here so that the size of the popup menu is updated?

        /**
         * Calling pack() works in this example, but I cannot call pack in the
         * actual application since there is a smooth transition animation when
         * clicking on the inner panel and pack() essentially re-adds the
         * components of the popup menu (removeNotify and addNotify is called),
         * which interferes with the animation and causes the menu to flicker.
         * The flickering when clicking the inner panel can also be seen in this
         * example when uncommenting the pack() call.
         */
        //popupMenu.pack();
        //
        // I tried combinations of the following, without success:
        //popupMenu.invalidate();
        //popupMenu.revalidate();
        //popupMenu.validate();
        //popupMenu.doLayout();

        // Repaint
        popupMenu.repaint();
    }

    public static void main(String args[]) {
        // Create popup child panel with height that changes when clicked
        resizingPanel = new JPanel(new BorderLayout());
        int initialHeight = 30;
        final JLabel label = new JLabel("Click me (" + initialHeight + "px)");
        resizingPanel.add(label);
        resizingPanel.setBackground(Color.GREEN);
        resizingPanel.setPreferredSize(new Dimension(PREFFERED_WIDTH, initialHeight));
        resizingPanel.addMouseListener(new MouseAdapter() {
            private int clickCount = 0;

            @Override
            public void mouseClicked(MouseEvent e) {
                int height = ((clickCount % 3) + 1) * 50;
                resizingPanel.setPreferredSize(new Dimension(PREFFERED_WIDTH, height));
                clickCount++;
                label.setText("Click me (" + height + "px)");
                resizePopupMenu();
            }
        });

        // Create popup
        popupMenu = new JPopupMenu();
        popupMenu.setLayout(new BorderLayout());
        popupMenu.add(new JLabel("Header"), BorderLayout.NORTH);
        popupMenu.add(resizingPanel, BorderLayout.CENTER);
        popupMenu.add(new JLabel("Footer"), BorderLayout.SOUTH);

        // Create frame
        frame = new PopupSizeTestFrame();
        frame.setLayout(new BorderLayout());
        frame.setPreferredSize(new Dimension(400, 400));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    popupMenu.show(frame, e.getX(), e.getY());
                }
            }
        });

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

运行上面的示例时,如果单击内部面板后关闭并打开了弹出菜单,则会看到弹出菜单的大小已更新,但是在弹出菜单可见时不会更新.

When running the example above you will see that the popup menu size is updated if it is closed and opened after the inner panel was clicked, but it is not updated while the popup is visible.

如何在resizePopupMenu()中更新JPopupMenu的高度?

What can I do in resizePopupMenu() to update the height of the JPopupMenu?

推荐答案

对于问题中的测试应用程序,弹出窗口始终是重量级组件,以下内容有效(如mKorbel的建议)

For the test app in the question the popup was always a heavyweight component and the following worked (as suggested by mKorbel)

private static void resizePopupMenu() {
    SwingUtilities.getWindowAncestor(popupMenu).pack();
}

对于实际的应用程序,当弹出窗口位于边界之内时,该应用程序被创建为轻量级组件,从而阻止了使用pack()调整其大小,并且还阻止了其超出应用程序边界的大小.

For the actual application when the popup was inside the bounds the application it was created as a lightweight component which prevented it from being resized with pack() and also prevented it from resizing past the application bounds.

我尝试设置此属性...

I tried setting this property...

JPopupMenu.setDefaultLightWeightPopupEnabled(false);

,但是随后创建了一个中等重量的组件,它仍然无法调整大小以超出应用程序范围.

but then a mediumweight component was created and it would still not resize past the application bounds.

因此,我必须首先使用以下不幸的代码来强制所有者"组件的所有弹出窗口都是重量级的

So I had to first force all popups of the "owner" component to be heavyweight with the following piece of unfortunate code

// Set owner to component on which popup is shown or any of its parents
final Component owner = ...;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
    @Override
    public Void run() {
        try {
            Field field;
            if (System.getProperty("java.version").startsWith("1.6.0")) {
                Class clazz = Class.forName("javax.swing.PopupFactory");
                field = clazz.getDeclaredField("forceHeavyWeightPopupKey");
            } else { //JDK 1.7.0, 1.8.0
                Class clazz = Class.forName("javax.swing.ClientPropertyKey");
                field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
            }
            field.setAccessible(true);
            owner.putClientProperty(field.get(null), Boolean.TRUE);
        } catch (Exception ex) {
            Exceptions.printStackTrace(ex);
        }
        return null;
    }
});

在强制弹出菜单始终是重量级组件之后

After forcing the popup menu to always be a heavyweight component this

SwingUtilities.getWindowAncestor(popupMenu).pack();

甚至还可以更新弹出窗口的大小,甚至超出了应用程序的范围.

also worked to update the size of the popup, even beyond the bounds of the application.

这篇关于可见时更新JPopupMenu高度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-30 23:23