---
title: Swingコンポーネントの再描画をJXLayerのDebugPainterを使ってデバッグ
author: aterai
pubdate: 2008-06-05
description: JXLayerのDebugPainterを使用したコンポーネントの再描画を可視化するjavaagentでデバッグを行います。
---
#contents

* 概要 [#summary]
`JXLayer`の`DebugPainter`を使用したコンポーネントの再描画を可視化する`javaagent`でデバッグを行います。

- [https://ateraimemo.com/data/swing/debugpainter.jar debugpainter.jar]
- [https://ateraimemo.com/data/swing/debugpainter_src.zip debugpainter_src.zip]

#ref(https://lh4.googleusercontent.com/_9Z4BYR88imo/TUFGtJHiIaI/AAAAAAAAAzs/ye6so-pxydw/s800/DebugPainterAgent.png)

* ソースコード [#sourcecode]
#code{{
package org.jdesktop.swinghelper.layer.demo;
import java.awt.*;
import java.lang.instrument.*;
import javax.swing.*;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.ext.DebugRepaintingUI;

public class DebugPainterAgent {
  public static void premain(String args) throws Exception {
    //System.out.println("premain");
    agentmain(args);
  }
  public static void agentmain(String args) throws Exception {
    System.out.println("agentmain start");
    new Thread() {
      @Override public void run() {
        System.out.println("Thread run");
        Frame[] list = Frame.getFrames();
        while (list.length==0) { //FIX ME!
          try {
            sleep(1000);
          } catch (Exception e) {
            e.printStackTrace();
          }
          System.out.print(".");
          list = Frame.getFrames();
        }
        System.out.println(" ");
        System.out.println("Loop out");
        replaceLayer();
        System.out.println("Thread exit");
      }
    } .start();
    System.out.println("agentmain end");
  }
  private static void replaceLayer() {
    for (Frame f:Frame.getFrames()) {
      if (f instanceof JFrame) {
        final JFrame frame = (JFrame)f;
        EventQueue.invokeLater(new Runnable() {
          @Override public void run() {
            System.out.println("replace layer");
            JComponent c = (JComponent)frame.getContentPane();
            JXLayer<JComponent> layer = new JXLayer<JComponent>(c);
            layer.setUI(new DebugRepaintingUI());
            frame.setContentPane(layer);
            frame.pack();
          }
        });
      }
    }
  }
}
}}

* 解説 [#explanation]
例えば、`repaint`が無限ループしているバグのあるサンプルを以下のように起動すると、`JLabel`の描画が無駄に繰り返され、`CPU`の使用率も異常になっている様子がすぐに分かります。
//--debugpainter.batをクリックします。
//--このデモに添付している TableCellProgressBar などは、JTableのセルや、ポップアップメニューを開いたときの再描画が分かりやすくて面白いかも。

- [https://java.net/projects/jxlayer Jxlayer — Project Kenai]から`jxlayer.jar`をダウンロードし、カレントもしくは、`.\lib`以下に配置
- [https://ateraimemo.com/data/swing/debugpainter.jar debugpainter.jar]をダウンロードし、カレントディレクトリに配置
-- または、ソース([https://ateraimemo.com/data/swing/debugpainter_src.zip debugpainter_src.zip])をダウンロードし、コンパイルして生成

#code{{
javac RepaintLoopTest.java
java -javaagent:debugpainter.jar RepaintLoopTest
REM java -javaagent:debugpainter.jar -jar example.jar
}}

#code{{
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class RepaintLoopTest {
  public JComponent makeUI() {
    String[] columnNames = {"String", "Integer", "Boolean"};
    Object[][] data = {
      {"aaa", 12, true}, {"bbb", 5, false},
      {"CCC", 92, true}, {"DDD", 0, false}
    };
    DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
    };
    JTable table = new JTable(model);
    table.setAutoCreateRowSorter(true);

    JLabel label = new JLabel("aaaaaaaaa") {
      int h = 10;
      int d = 1;
      @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        repaint(); //BUG: an infinite repaint loop
      }
    };
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    p.add(label, BorderLayout.SOUTH);
    p.setPreferredSize(new Dimension(320, 240));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new RepaintLoopTest().makeUI());
    f.pack(); //setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
}}

* 参考リンク [#reference]
- %%[https://jxlayer.dev.java.net/ jxlayer: Project Home Page]%%
- %%[https://java.net/projects/jxlayer Jxlayer — Project Kenai]%%
- %%[http://weblogs.java.net/blog/alexfromsun/archive/2007/11/debug_swing_rep.html Alexander Potochkin's Blog: Debug Swing repainting]%%
- %%[http://weblogs.java.net/blog/alexfromsun/archive/2008/06/the_new_jxlayer.html Alexander Potochkin's Blog: JXLayer 3.0 - Getting started]%%
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/JComponent.html#setDebugGraphicsOptions-int- JComponent (Java Platform SE 8)]
-- [http://www.java2s.com/Tutorial/Java/0240__Swing/DebugGraphics.htm DebugGraphics : DebugGraphics « Swing « Java Tutorial]
-- `DebugGraphicsOptions`を設定して、コンポーネントの描画を逐次表示してデバックする
- [[DebugGraphicsを使用してJComponentの描画をデバッグする>Swing/DebugGraphics]]
-- `DebugGraphicsOptions`を設定してコンポーネントの描画を逐次遅延してデバックする
- [http://www.java2s.com/Tutorial/Java/0240__Swing/DebugGraphics.htm DebugGraphics : DebugGraphics « Swing « Java Tutorial]

* コメント [#comment]
#comment
#comment