Непрозрачный фон JButton в окне не верхнего уровня становится непрозрачным?

Прежде чем вы начнете читать, вот несколько пояснений о том, о чем идет речь:

  1. SSCCE предназначен для Java 7. Можно было бы использовать sun.*.AWTUtilities, чтобы адаптировать его к Java 6, но мне все равно, как он работает на Java 6.
  2. Линия разлома: [...]new JDialog(someWindow). Дублирование можно исправить в SSCCE, просто изменив эту строку на [...]new JDialog().

Почему в окнах верхнего уровня не появляются ореолы?


Ожидаемое поведение: final JDialog d = new JDialog() (см. SSCCE) как окна TL, так и окна без TL имеют полупрозрачный фон

Как видите, правое окно имеет полупрозрачный фон (как и ожидалось).

Фактическое поведение: final JDialog d = new JDialog(f) (см. SSCCE) окно TL показывает полупрозрачный фон, в то время как фон без TL становится непрозрачным даже после однократной перерисовки

В этом случае правое окно имеет непрозрачный фон. На самом деле требуется 3-4 перерисовки по любой причине (проще всего воспроизвести перерисовку при ролловере), чтобы фон стал полностью непрозрачным.


SSCCE:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.synth.ColorType;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthConstants;
import javax.swing.plaf.synth.SynthContext;
import javax.swing.plaf.synth.SynthLookAndFeel;
import javax.swing.plaf.synth.SynthPainter;
import javax.swing.plaf.synth.SynthStyle;
import javax.swing.plaf.synth.SynthStyleFactory;

public class SynthSSCCE
{
        public static void main(String[] args) throws Exception
        {
                final SynthLookAndFeel laf = new SynthLookAndFeel();
                UIManager.setLookAndFeel(laf);
                SynthLookAndFeel.setStyleFactory(new StyleFactory());

                SwingUtilities.invokeLater(new Runnable()
                {
                        @Override
                        public void run()
                        {
                                final JFrame f = new JFrame();
                                {
                                        f.add(new JButton("Works properly"));
                                        f.setUndecorated(true);
                                        f.setBackground(new Color(0, true));
                                        f.setSize(300, 300);
                                        f.setLocation(0, 0);
                                        f.setVisible(true);
                                }
                                {
                                        final JDialog d = new JDialog(f);
                                        final JButton btn = new JButton("WTF?");
                                        // uncomment and notice that this has no effect
                                        // btn.setContentAreaFilled(false);
                                        d.add(btn);
                                        d.setUndecorated(true);
                                        d.setBackground(new Color(0, true));
                                        d.setSize(300, 300);
                                        d.setLocation(320, 0);
                                        d.setVisible(true);
                                }
                        }
                });
        }

        static class StyleFactory extends SynthStyleFactory
        {
                private final SynthStyle style = new Style();

                @Override
                public SynthStyle getStyle(JComponent c, Region id)
                {
                        return style;
                }
        }

        static class Style extends SynthStyle
        {
                private final SynthPainter painter = new Painter();

                @Override
                protected Color getColorForState(SynthContext context, ColorType type)
                {
                        if (context.getRegion() == Region.BUTTON && type == ColorType.FOREGROUND)
                                return Color.GREEN;

                        return null;
                }

                @Override
                protected Font getFontForState(SynthContext context)
                {
                        return Font.decode("Monospaced-BOLD-30");
                }

                @Override
                public SynthPainter getPainter(SynthContext context)
                {
                        return painter;
                }

                @Override
                public boolean isOpaque(SynthContext context)
                {
                        return false;
                }
        }

        static class Painter extends SynthPainter
        {
                @Override
                public void paintPanelBackground(SynthContext context, Graphics g, int x, int y, int w, int h)
                {
                        final Graphics g2 = g.create();
                        try
                        {
                                g2.setColor(new Color(255, 255, 255, 128));

                                g2.fillRect(x, y, w, h);
                        }
                        finally
                        {
                                g2.dispose();
                        }
                }

                @Override
                public void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h)
                {
                        final Graphics g2 = g.create();
                        try
                        {
                                if ((context.getComponentState() & SynthConstants.MOUSE_OVER) == SynthConstants.MOUSE_OVER)
                                        g2.setColor(new Color(255, 0, 0, 255));
                                else
                                        g2.setColor(new Color(0xAA, 0xAA, 0xAA, 255));
                                g2.fillRoundRect(x, y, w, h, w / 2, h / 2);
                        }
                        finally
                        {
                                g2.dispose();
                        }
                }
        }
}

И это мои вопросы...

  1. Что происходит? Например, почему это демонстрирует поведение настраиваемого непрозрачного компонента, который забывает вызвать super?
  2. Почему этого не происходит с окнами TL?
  3. Как проще всего это исправить, кроме как не использовать окна без TL?

person afk5min    schedule 29.08.2013    source источник
comment
Пожалуйста, вставьте свой код SSCCE сюда, а не в ссылку.   -  person Hovercraft Full Of Eels    schedule 29.08.2013
comment
Заменил ссылку полным кодом.   -  person afk5min    schedule 29.08.2013
comment
не знаю, скомпилирован ли он в Java7   -  person mKorbel    schedule 29.08.2013
comment
@mKorbel: К сожалению, код, представленный в этом вопросе / ответах, ЯВНО ИЗБЕГАЕТ от любых окон, отличных от TL. Меня не волнует, что super("Test translucent window"); работает нормально, потому что мне нужны окна без TL, которые, к сожалению, демонстрируют какое-то странное поведение.   -  person afk5min    schedule 29.08.2013
comment
угу, но у меня работает в Java6...   -  person mKorbel    schedule 29.08.2013
comment
@mKorbel: я думал о добавлении SSCCE Java 6 с основанным на отражении AWTUtilities#setWindowOpaque(Window, boolean), но опять же, Java 6 уже давно был EoLed. Бесполезно исследовать, как это работает на устаревших технологиях...   -  person afk5min    schedule 30.08.2013
comment
интересно ...., вы должны признать, что важен порядок методов, согласованность кода, порядок ожидаемых событий, иначе вы, вероятно, устаревший кодер, извините, изменения в Java7 нарушают все стандарты, часть правил безопасности не делает этого без грязные хаки, если вы хотите распространять хаки, а затем компилировать в Java7, остальное использовать Java6 или ждать Java8, правда в том, что любые методы в Swing не изменяются вместе с изменениями в остальных классах Java (основных)   -  person mKorbel    schedule 30.08.2013
comment
давайте продолжим это обсуждение в чате   -  person afk5min    schedule 30.08.2013
comment
хммм (снова протестировано) теперь я смущен, вижу это как ошибку, теперь не уверен, для Java6 или Java7, особенно почему JDialog прозрачен в Win8/Java7, но убедитесь, что setContentAreaFilled работает правильно, потому что вам нужно переопределить paintText и paintIcon для экземпляра JButton, создайте собственный SyntButtonUI, я опубликую свое тестирование в качестве ответа здесь   -  person mKorbel    schedule 30.08.2013
comment
@mKorbel: «вы должны переопределить paintText и paintIcon для экземпляра JButton»: если бы я хотел иметь свой собственный пользовательский интерфейс и компоненты Swing Swing, такие как JOptionPane, JFileChooser и т. д., которые всегда будут использовать значения по умолчанию JButton/JPanel, то я бы определенно Сделай так. «создать собственный SyntButtonUI»: это не то, как работает Synth. Да, я уже думал об инструментировании классов Synth (потому что вы не можете предоставить свои собственные ComponentUI), но я хотел бы сделать это в крайнем случае.   -  person afk5min    schedule 30.08.2013
comment
Я говорю о стандартном способе, вы можете делать все, что хотите.   -  person mKorbel    schedule 30.08.2013


Ответы (2)


требуется 3-4 перерисовки по любой причине (проще всего воспроизвести перерисовку при ролловере), чтобы фон стал полностью непрозрачным.

Ознакомьтесь с разделом Фон с прозрачностью, который должен дать вам некоторое представление о эта проблема.

Я никогда не играл с Synth, поэтому не знаю, сработает ли то же решение или нет.

person camickr    schedule 29.08.2013
comment
Synth не следует общему мнению L&F до Nimbus о том, что непрозрачный компонент — это такой компонент, который закрашивает свой фон, и наоборот. Synth позволяет непрозрачным компонентам закрашивать свой фон, как это должно быть (для некоторых компонентов isContentAreaFilled в UIDefaults контролирует, закрашивается ли фон). Главный вопрос: почему все работает в окнах TL, но не работает в окнах без TL? - person afk5min; 29.08.2013

Почему в окнах верхнего уровня не появляются ореолы?

Согласно Oracle (учебники по Java):

Каждый контейнер верхнего уровня имеет панель содержимого, которая, вообще говоря, содержит (прямо или косвенно) видимые компоненты в графическом интерфейсе этого контейнера верхнего уровня.

http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html

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

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

Следовательно, как вы использовали

final Graphics g2 = g.create();

Если у вас есть javax.swing.JComponent.paintComponent, переопределенный в методе, противоположном созданию графического объекта самостоятельно, он должен смягчить прозрачность с помощью super.g();

Исправьте это, создав отдельный метод, указанный выше, для графики.

person Jebathon    schedule 07.09.2013
comment
серьезно сомневаюсь, что стекло как-то связано с проблемой: f.i. как это объясняет различное поведение нового JDialog() по сравнению с новым JDialog(frame)? - person kleopatra; 07.09.2013
comment
Все компоненты добавляются на панель содержимого. Стеклянная панель полностью не используется (можно увидеть в SSCCE). - person afk5min; 07.09.2013