TITLE:JFrameの透明化と再描画
Posted by aterai at 2011-10-24

JFrameの透明化と再描画

半透明にしたJFrameの再描画を行います。
  • category: swing folder: TranslucentFrameRepaint title: JFrameの透明化と再描画 tags: [JFrame, JRootPane, Translucent, JPanel, JLabel, TexturePaint, Clock] author: aterai pubdate: 2011-10-24T15:53:52+09:00 description: 透明にしたJFrameに半透明のデジタル時計を配置し、文字更新による背景色の再描画をテストします。 image: https://lh4.googleusercontent.com/-ujoDf8eD4vE/TqLcC0f2CHI/AAAAAAAABD4/LHaXXW6HW1k/s800/TranslucentFrameRepaint.png hreflang:
       href: https://java-swing-tips.blogspot.com/2014/02/translucent-jframe-repaint.html
       lang: en

概要

透明にしたJFrameに半透明のデジタル時計を配置し、文字更新による背景色の再描画をテストします。
TranslucentFrameRepaint.png

サンプルコード

#spanend
#spandel
private final SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
#spanend
#spandel
private final JLabel label = new JLabel(df.format(new Date()));
#spanend
#spandel
private final Timer timer = new Timer(1000, new ActionListener() {
#spanend
  @Override public void actionPerformed(ActionEvent e) {
    label.setText(df.format(new Date()));
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
#spanend
#spanadd
JLabel label = new JLabel(LocalTime.now().format(formatter), SwingConstants.CENTER);
#spanend
#spanadd
Timer timer = new Timer(100, null);
#spanend
#spanadd
timer.addActionListener(e -> {
#spanend
  label.setText(LocalTime.now().format(formatter));
  Container parent = SwingUtilities.getUnwrappedParent(label);
  if (Objects.nonNull(parent) && parent.isOpaque()) {
    repaintWindowAncestor(label);
  }
});
#spandel
private void repaintWindowAncestor(Component c) {
#spanend
  Window w = SwingUtilities.getWindowAncestor(c);
  if(w instanceof JFrame) {
    JFrame f = (JFrame)w;
    JComponent cp = (JComponent)f.getContentPane();
    //cp.repaint();
    Rectangle r = c.getBounds();
    r = SwingUtilities.convertRectangle(c, r, cp);
    cp.repaint(r.x, r.y, r.width, r.height);
    //r = SwingUtilities.convertRectangle(c, r, f);
    //f.repaint(r.x, r.y, r.width, r.height);
  }else{
    c.repaint();
#spanadd
// ...
#spanend
#spanadd
private void repaintWindowAncestor(JComponent c) {
#spanend
  JRootPane root = c.getRootPane();
  if (root == null) {
    return;
  }
  Rectangle r = SwingUtilities.convertRectangle(c, c.getBounds(), root);
  root.repaint(r.x, r.y, r.width, r.height);
}

解説

上記のサンプルでは、実際はJFrameが半透明ではなく、以下のように半透明にした透明にしたJFrameに、半透明のJPanelを追加、さらにその子として一秒ごとに文字列が変化するJLabel(時計)を配置しています。

解説

上記のサンプルでは、実際はJFrameが半透明ではなく、以下のように透明にしたJFrameに半透明のJPanelを追加、さらにその子として一秒ごとに文字列が変化するJLabel(時計)を配置しています。
  • JFrame
    • 透明
  • JFrame
    • 透明
      #spandel
      com.sun.awt.AWTUtilities.setWindowOpaque(frame, false);
      #spanend
      #spandel
      //frame.setBackground(new Color(0,0,0,0)); //1.7.0
      #spanend
      #spanadd
      com.sun.awt.AWTUtilities.setWindowOpaque(frame, false); // JDK 1.6.0
      #spanend
      #spanadd
      frame.setBackground(new Color(0x0, true)); // JDK 1.7.0以降
      #spanend
      
    • AWTUtilities.setWindowOpacity(...)、Window#setOpacity(...)は子コンポーネント全体が半透明になるので、このサンプルでは使用していない
  • JPanel
    • frame.getContentPane().add(panel)で追加
    • 半透明(二種類)
      • setOpaque(true)+半透明のアルファ成分をもつ色をsetBackground()で設定
      • setOpaque(false)+paintComponent()をオーバーライドして背景画像などを描画
  • JLabel
    • panel.add(label)で追加
    • 一秒ごとに文字列を変更する時計
    • setOpaque(false)で透明
    • Window#setOpacity(...)(またはJDK 1.6.0AWTUtilities.setWindowOpacity(...))は子コンポーネントを含めてすべて半透明になるので、このサンプルでは使用していない
JFrameが半透明なので、JFrame自体は透明ですが、そのContentPaneから再描画しないと、JLabelとの間にあるContainerの背景色などが重複して上書きされる(色が濃くなる)ようです。
  • JPanel
    • frame.getContentPane().add(panel)で追加
    • 半透明(二種類)
      • setOpaque(true)+半透明のアルファ成分をもつ色をsetBackground()で設定
      • JPanelsetOpaque(true)なのでContentPaneから再描画しないとJPanelに設定した半透明の背景色が重複して上書きされる(色が濃くなる)
      • setOpaque(false)+paintComponent()をオーバーライドして背景画像などを描画

参考リンク

コメント

参考リンク

コメント