Установка прозрачного фона JFrame делает PopupMenu пустым

Мой вопрос похож на это, но я думаю имеет более простой пример.

В основном, вызывая AWTUtilities.setWindowOpaque(window, false), чтобы сделать фон JFrame прозрачным, мой JPopupMenu иногда отображается как пустой.

public class JavaApplication8 {

    JPopupMenu popup;
    JMenuItem open;
    JLabel bgLabel = new JLabel("testing");

    public static void main(String[] args) {
        // TODO code application logic here

        JFrame window = new JFrame("test");

        URL bgURL = JavaApplication8.class.getResource("images/bg.jpg");
        ImageIcon bg = new ImageIcon(bgURL);

        JavaApplication8 test = new JavaApplication8();
        test.setPopupMenu();
        test.bgLabel.setIcon(bg);

        window.add(test.bgLabel, BorderLayout.CENTER);

        window.setUndecorated(true);
        AWTUtilities.setWindowOpaque(window, false);        
        //window.pack();
        window.setSize(200, 200);
        window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        window.setLocationRelativeTo(null);
        window.setVisible(true);

    }

    public void setPopupMenu(){
        popup = new JPopupMenu();
        open = new JMenuItem("Test");

        popup.add(open);
        this.bgLabel.setComponentPopupMenu(popup);     
    }

}

Вот изображение того, что происходит:

введите здесь описание изображениявведите здесь описание изображения

Что интересно, это происходит всякий раз, когда я нажимаю на правую сторону JFrame. Не уверен, почему. Имейте в виду, что я не уверен на 100%, что AWTUtilities.setWindowOpaque(window, false) действительно является причиной этой проблемы, однако всякий раз, когда я удаляю эту строку, все идет нормально.

РЕДАКТИРОВАТЬ: Как указано camickr, looks like this happens when the popup menu is not fully contained in the bounds of the parent window.


person kir    schedule 16.08.2013    source источник
comment
Как ни странно... Java 6 и Windows 7 - без проблем, Java 7 и Windows 7 - без проблем...   -  person MadProgrammer    schedule 16.08.2013
comment
@MadProgrammer: Правда? Я на Java 7 и Windows 7, хммм.   -  person kir    schedule 16.08.2013
comment
JPopupMenus по умолчанию являются легкими, когда они полностью содержатся в окне. Проблема возникает, когда какая-либо часть всплывающего окна должна появиться за пределами окна — тогда для всплывающего окна создается новое тяжелое окно. Проблема проявляется только в этом тяжелом окне.   -  person Lunchbox    schedule 22.08.2013


Ответы (2)


Фон: я не уверен, почему использование прозрачного/полупрозрачного фона вызывает проблемы с тяжелыми всплывающими окнами и тем, как они отображаются, но это происходит — независимо от того, используете ли вы AWTUtilities.setWindowOpaque(window, false) или frame.setBackground(new Color(0, 0, 0, 0)).

HeavyWeightPopup создаются, когда всплывающее окно не может полностью поместиться внутри целевого окна. Таким образом, +User2280704 ваша проблема также возникает, если вы щелкнете в самом низу окна. LightWeightPopup не имеют этой проблемы — следовательно, меню работают в середине вашего окна.

Кроме того, интересно отметить, что обычно меню отображается нормально в первый раз, но не в последующие разы.

Ответ: я придумал обходной путь, который вызывает перерисовку после отображения любого всплывающего окна. Просто вызовите следующий код при запуске приложения.

PopupFactory.setSharedInstance(new PopupFactory() 
{
    @Override
    public Popup getPopup(Component owner, final Component contents, int x, int y) throws IllegalArgumentException
    {
        Popup popup = super.getPopup(owner, contents, x, y);
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                contents.repaint();
            }
        });
        return popup;
    }
});
person Lunchbox    schedule 22.08.2013
comment
Я все еще новичок в Java, поэтому я действительно не знаю, что вы имели в виду, вызывая следующий код при запуске вашего приложения. Не хотите уточнить еще немного? Прошу прощения за беспокойство. - person kir; 23.08.2013
comment
Нет проблем, просто вставьте этот код куда-нибудь и убедитесь, что он выполняется до того, как появится ваше первое всплывающее окно. Вам нужно позвонить только один раз. Итак, в простейшем случае вы можете поместить его в любом месте вашего основного метода. - person Lunchbox; 23.08.2013

это происходит всякий раз, когда я нажимаю на правую сторону JFrame

Похоже, это происходит, когда всплывающее меню не полностью находится в границах родительского окна. Не знаю, как это исправить.

В Java 7 вы можете использовать:

frame.setBackground(new Color(0, 0, 0, 0));

для прозрачности.

person camickr    schedule 16.08.2013
comment
В чем разница между frame.setBackground(new Color(0, 0, 0, 0)); и AWTUtilities.setWindowOpaque(window, false);? К сожалению, это также не решило проблему. - person kir; 16.08.2013
comment
Да я только что протестировал. Я обнаружил, что всплывающее окно отображается как пустое с правой стороны, но если вы переместите мышь в белую область, появится текст. До сих пор понятия не имею, почему. Разница в том, что в JDK7 прозрачность является частью API, вам не нужно использовать служебный класс, который не поддерживается. Так что, по-видимому, код лучше реализован (хотя эта проблема указывает на обратное). - person camickr; 16.08.2013
comment
есть важные изменения, все идет к **, контейнер не должен быть декорирован, L&F должен быть SystemL&F, важно порядок кода, в данный момент я бы посоветовал не использовать AWTUtilities в Java7 без особых причин или без согласия idioti*c ограничений, интересно то, что вы можете изменить все на 2-й. контейнер, в случае, если выезжает 1-й. как нетронутый - person mKorbel; 16.08.2013