0

ループを使用して、ダブルバッファリングペインティングを呼び出しています。これは、私の唯一のPanelの再描画メソッドをオーバーライドするとともに、再描画の完全な制御をループに渡し、必要な場合にのみレンダリングするように設計されています(つまり、GUIで何らかの変更が行われました)。

これは私のレンダリングルーチンです:

    Log.write("renderer painting");

    setNeedsRendering(false);

    Graphics g = frame.getBufferStrategy().getDrawGraphics();

    g.setFont(font);
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, window.getWidth(),window.getHeight());

    if(frame != null)
        window.paint(g);

    g.dispose();

    frame.getBufferStrategy().show();

ご覧のとおり、これはかなり標準的なものです。バッファストラテジー(2に初期化)からgrpahicsオブジェクトを取得し、それをすべて黒にして、「window」オブジェクトのpaintメソッドに渡します。

グラフィックオブジェクトを使用してウィンドウが完成したら、それを破棄し、バッファ戦略でshowを呼び出して、仮想バッファの内容を表示します。

ウィンドウがグラフィックスオブジェクトを他の多くの子コンポーネントに渡し、ウィンドウにデータを入力し、各コンポーネントがグラフィックスオブジェクトの同じインスタンスを使用して、テキスト、図形、画像などを画面に描画することに注意してください。

システムが実行され、大きな画像がレンダリングされると、問題が発生し始めます。画像はいくつかの断片にカットされ、画像がレンダリングされるはずの場所の内側に異なるオフセットで何度も(3〜4回)描画されているように見えます。私の添付画像を参照してください:

これは元の画像です: 代替テキストhttp://img109.imageshack.us/img109/8308/controller.png

これは私が得るものです: 代替テキストhttp://img258.imageshack.us/img258/3248/probv.png

2番目の画像では、画像上に図形をレンダリングしていることに注意してください。これらは常に正しい位置にあります。

なぜこれが起こっているのか考えていますか?g.drawImage(...)を呼び出す直前に、画像をメモリ内にあるようにファイルに保存すると、元の画像と同じになります。

4

1 に答える 1

2

ええと、あなたはスイングを使用していますか?
通常、Swingは画像を自動的にレンダリングしますが、オフにすることはできません。Swingには、AWTウィジェットのメソッド互換性と、必要な場合にのみ描画を含むいくつかの最適化のために非常に複雑なレンダリングルーチンがあるため、repaint()メソッドは範囲外です。High-Speed Drawing APIを使用する場合は、JFrameやWindowなどのBufferStrategyを備えたコンポーネントを使用します。

setIgnoreRepaint(false);

Swingレンダリングをオフにするには、描画ループを設定し、コンテンツ自体をペイントします。または、OpenGLレンダリングにJOGLを使用できます。使用している方法は、Java2Dの正しい使用法とは完全に相容れないようです。

ここで正しい使用法:

public final class FastDraw extends JFrame {
  private static final transient double NANO = 1.0e-9;


 private BufferStrategy bs;

 private BufferedImage frontImg;

 private BufferedImage backImg;

 private int PIC_WIDTH,
             PIC_HEIGHT;

  private Timer timer;

  public FastDraw() {
    timer = new Timer(true);
    JMenu menu = new JMenu("Dummy");
    menu.add(new JMenuItem("Display me !"));
    menu.add(new JMenuItem("Display me, too !"));
    JMenuBar menuBar = new JMenuBar();
    menuBar.add(menu);
    setJMenuBar(menuBar);

    setIgnoreRepaint(true);
    setVisible(true);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) {
        super.windowClosing(evt);
        timer.cancel();
        dispose();
        System.exit(0);
      }
    });
    try {
      backImg = javax.imageio.ImageIO.read(new File("MyView"));
      frontImg = javax.imageio.ImageIO.read(new File("MyView"));
    }
    catch (IOException e) {
      System.out.println(e.getMessage());
    }
    PIC_WIDTH = backImg.getWidth();
    PIC_HEIGHT = backImg.getHeight();
    setSize(PIC_WIDTH, PIC_HEIGHT);


    createBufferStrategy(1); // Double buffering
    bs = getBufferStrategy();
    timer.schedule(new Drawer(),0,20);
  }
  public static void main(String[] args) {
    new FastDraw();
  }

  private class Drawer extends TimerTask {

    private VolatileImage img;

    private int count = 0;

    private double time = 0;

    public void run() {
      long begin = System.nanoTime();
      Graphics2D  g  = (Graphics2D) bs.getDrawGraphics();
      GraphicsConfiguration gc = g.getDeviceConfiguration();
      if (img == null)
        img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
      Graphics2D g2 = img.createGraphics();
      // Zeichenschleife
      do {
        int valStatus = img.validate(gc);
        if (valStatus == VolatileImage.IMAGE_OK)
          g2.drawImage(backImg,0,0,null);
        else {
          g.drawImage(frontImg, 0, 0, null);
        }
        // volatile image is ready
        g.drawImage(img,0,50,null);
        bs.show();
      } while (img.contentsLost());
      time = NANO*(System.nanoTime()-begin);
      count++;
      if (count % 100 == 0)
        System.out.println(1.0/time);
    }
  }
于 2010-01-19T21:46:31.263 に答える