Javenue logo

Javenue

Программирование на Java

Информационные технологии

Прозрачные окна в Java Swing

Ура! Начиная с версии Java 1.7 прозрачные и полупрозрачные окна в Java Swing стали реальностью.

В этой статье вы найдете пример кода для создания полупрозрачного JFrame. И как бонус сможете посмотреть как извращались люди до появления этой замечательной функциональности.

Поддержка прозрачности на данный момент имеет 3 формы:

  • однотонная прозрачность (uniform) - каждая точка окна имеет одно и то же значение прозрачности - alpha;
  • попиксельная прозрачность (per-pixel) - можно указать значение opacity для каждой точки. С это фичей можно делать, например, градиентные окна;
  • прозрачность на основе форм - можно создать окно на основе Shape, например, круглой формы, и указать для него либо однотонную прозрачность, либо попиксельную прозрачность.

Есть только одна проблема - пока еще не все платформы поддерживают возможность отрисовки прозрачных окон. Соответственно нужна специальная проверка.

Пример прозрачного JFrame

Предлагаю рассмотреть фрагмент кода для создания окна с однотонной прозрачностью.

public class Translucent extends JFrame {
    public Translucent() {
        super("Translucent JFrame");
        setLayout(new GridLayout());

        setBounds(400, 300, 300, 200);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        add(new JLabel("Translucent Window Demo"));
    }

    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Translucent window = new Translucent();

                if (translucencySupported())
                    window.setOpacity(0.5f);

                window.setVisible(true);
            }
        });
    }

    public static boolean translucencySupported() {
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();

        return gd.isWindowTranslucencySupported(
                GraphicsDevice.WindowTranslucency.TRANSLUCENT);
    }
}

Если платформа не поддерживает прозрачность, то при попытке вызова метода setOpacity возникнет UnsupportedOperationException. Для этого и была добавлена проверка translucencySupported().

Вот что получится в результате выполнения программного кода:


Translucent JFrame Demo

На этом все. Дальше читайте на свой страх и риск :)

Эмулируем прозрачность окна на ранних версиях Java

В далеком 2007 году, когда библиотека Java Swing еще не предоставляла возможности создания прозрачных окон без использования native кода, я наткнулся на одну интересную статью. В ней рассказывается, как можно без этого самого native кода сделать "прозрачные" окошки в Java Swing. Реализуется это при помощи хитрого хака:

  • Делаем скриншот перед прорисовкой окна.
  • Используем этот screenshot как background фон для нашего окошка.
  • Располагаем все это дело так, чтобы реальное изображение экрана и фон окна совпадали - соответственно, создастся иллюзия прозрачного окна.

Для того, чтобы сделать скриншот экрана, можно воспользоваться методом createScreenCapture из класса java.awt.Robot. В статье мне не понравилась фраза, что мол это все просто, а вот сделать, чтобы окно обновлялось при изменении и перемещении окна - намного сложнее.

Данное заявление было опровергнуто буквально через 2 минуты.

Достаточно было навесить Listener на объект JFrame, который бы перерисовывал background.

А вот собственно и код на Java (импорт классов опущен):

public class TransparentBackground extends JComponent {
   private JFrame frame;
   private Image background;

   public TransparentBackground(JFrame frame) {
       this.frame = frame;
       updateBackground();
   }

   public void updateBackground() {
       try {
           Robot rbt = new Robot();
           Toolkit tk = Toolkit.getDefaultToolkit();
           Dimension dim = tk.getScreenSize();
           background = rbt.createScreenCapture(
                   new Rectangle(0, 0, (int) dim.getWidth(),
                           (int) dim.getHeight()));
       } catch (Exception ex) {
           ex.printStackTrace();
       }
   }

   public void paintComponent(Graphics g) {
       Point pos = this.getLocationOnScreen();
       Point offset = new Point(-pos.x, -pos.y);
       g.drawImage(background, offset.x, offset.y, null);
   }

   private static class TransparentComponentListener
           implements ComponentListener {

       public void componentResized(ComponentEvent e) {
           Component[] components = ((JFrame) e.getComponent())
                   .getContentPane().getComponents();
           components[0].repaint();
       }

       public void componentMoved(ComponentEvent e) {
           componentResized(e);
       }

       public void componentShown(ComponentEvent e) {
           componentResized(e);
       }

       public void componentHidden(ComponentEvent e) {
           componentResized(e);
       }
   }

   public static void main(String[] args) {
       JFrame frame = new JFrame("Transparent Window");
       frame.addComponentListener(new TransparentComponentListener());
       TransparentBackground bg = new TransparentBackground(frame);
       bg.setLayout(new BorderLayout());

       JButton button = new JButton("This is a button");
       bg.add("North", button);

       JLabel label = new JLabel("This is a label");
       bg.add("South", label);

       frame.getContentPane().add("Center", bg);
       frame.pack();
       frame.setSize(200, 200);
       frame.show();
   }
}

Вот результат выполнения программы:


Transparent Window in Java Swing

А оригинал статьи находится здесь.



Комментариев: 0

  Выйти

  * для публикации комментариев нужно