ペイント()/ペイントコンポーネント()が呼び出されないのはなぜですか?

StackOverflow https://stackoverflow.com/questions/1676187

  •  16-09-2019
  •  | 
  •  

質問

この 2 日間、私は次のことを試みました 理解する Java がグラフィックスを処理する方法ですが、それだけで惨めに失敗しました。私の主な問題は、paint() (または新しいPaintComponent())がいつどのように呼び出されるのか、呼び出されるべきなのかを正確に理解することです。

いつ作成されるかを確認するために作成した次のコードでは、自分で手動で呼び出しを追加するか、JFrame.paintAll()/JFrame.paintComponents() を呼び出さない限り、paintComponent() は呼び出されません。

(repaint() であっても) 呼び出されないという問題が解決することを期待して、paint() メソッドの名前をpaintComponent() に変更しましたが、うまくいきませんでした。

package jpanelpaint;

import java.awt.*;
import javax.imageio.*;
import javax.swing.*;
import java.io.*;
import java.util.ArrayList;

public class ImageLoadTest extends JComponent {
 ArrayList<Image> list;

 public ImageLoadTest() {
  list = new ArrayList<Image>();

  try { //create the images (a deck of 4 cards)
   for(String name : createImageFileNames(4)){
    System.err.println(name);
    list.add(ImageIO.read(new File(name)));
   }
  } catch (IOException e) {  }
 }

    protected void paintComponent(Graphics g) {
     int yOffset=0;
  System.err.println("ImageLoadTest.paintComponent()");
     for(Image img : list) {
      g.drawImage(img, 0, yOffset,  null);
      yOffset+=20;
     }
    }

 public static void main(String args[]) throws InterruptedException {
  JFrame frame = new JFrame("Empty JFrame");
  frame.setSize(new Dimension(1000, 500));
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  frame.setVisible(true);

  Thread.sleep(1000);
  frame.setTitle("Loading images");
  ImageLoadTest ilt = new ImageLoadTest();
  frame.add(ilt);
  //update the screen
  //DOESN'T WORK. only works if I call frame.paintAll(frame.getGraphics()) 
  ilt.repaint();
  frame.repaint();

  Thread.sleep(1000);
  frame.setTitle("Setting background");
  ilt.setBackground(Color.BLACK);
  //update the screen - DOESN'T WORK even if I call paintAll ..
  ilt.repaint();
  frame.repaint();

            //have to call one of these to get anything to display  
//  ilt.paintComponent(frame.getGraphics()); //works
  frame.paintComponents(frame.getGraphics()); //works
 }

 //PRIVATE HELPER FUNCTIONS

 private String[] createImageFileNames(int count){
  String[] fileNames = new String[count];
  for(int i=0; i < count; i++)
   fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp";  
  return fileNames;
 }
}
役に立ちましたか?

解決 4

元のコードが機能しない原因となった主な問題は次のとおりです。

  1. add() 操作の後に validate() を呼び出さない
  2. コンポーネントの優先サイズを設定しない。
  3. Super.paintComponent()を呼び出しないときにそれをオーバーライドするとき(これにより、setbackground()呼び出しが機能しません)
  4. JPanel を描画するには JPanel から継承する必要がありました。コンポーネントも JComponent も、ポイント 3 を修正した場合でも、setBackground() 呼び出しが機能するには十分ではありませんでした。

上記の作業を行った後は、paintComponent メソッドを呼び出しても、paint メソッドを呼び出しても、最初にスーパー コンストラクターを呼び出すことを覚えていれば、どちらも機能するようでした。

この情報は、@jitter、@tackline、@camickr が書いたものから集められたもので、大変賞賛に値します。

追伸自分の質問に答えることが悪い形式とみなされるかどうかはわかりませんが、必要な情報はいくつかの回答から集められたものであるため、他の回答を更新してこのように要約を書くのが最良の方法だと思いました。

他のヒント

コンポーネントは、「ゼロサイズ」を持っているとRepaintMangerが無いサイズで何かを試してみて、ペイントしないように十分にスマートであるため、

paintComponent()が元のコードで呼び出されない理由の一つです。

あなたは、フレームにコンポーネントを追加して、フレーム見えるようにする場合、レイアウトマネージャがコンポーネントをレイアウトするために呼び出されるので、

コードの並べ替えが働く理由があります。デフォルトでは、フレームはのBorderLayoutを使用し、デフォルトでコンポーネントは、それがペイントされますように、コンポーネントに利用可能なすべてのスペースを与える起こるのBorderLayoutの中央に追加されます。

ただし、FlowLayoutのがゼロであるコンポーネントの推奨サイズを尊重するので、あなたはまだ問題を抱えているだろう、FlowLayoutのように、コンテンツ・ペインのレイアウトマネージャを変更します。

あなたが本当にレイアウトマネージャは、自分の仕事を行うことができますので、あなたにあなたのコンポーネントを適切なサイズを割り当てている何をする必要があるか。

ここでの大きな問題の 1 つは、スイング コンポーネントを更新していないことです。 イベントディスパッチスレッド (EDT). 。main メソッド内のすべてのコードを次のようにラップしてみてください。

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            // swing code here...             
        }
    });

また:フレームを表示するように設定する前に、ImageLoadTest をフレームに追加してください。これは、コードをざっと読んだことに基づいています。さらにコードを読んで、他に何が見つかるか見ていきます。

編集:

上記の最初のアドバイスに従って、メイン メソッドを次のように単純化すると、paintComponent() が呼び出されます。

public static void main(String args[]) throws InterruptedException {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Empty JFrame");
            frame.setSize(new Dimension(1000, 500));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            PaintComponentTest ilt = new PaintComponentTest();
            frame.add(ilt);
            frame.setVisible(true);
            ilt.setBackground(Color.BLACK);
        }
    });
}

また、アニメーションを実行するためのタイマーの使用や、一般的な Swing イベントのディスパッチ、さまざまなペイント メソッドをいつどのようにオーバーライドするかについても読みました。

http://java.sun.com/products/jfc/tsc/articles/painting/

http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html

http://java.sun.com/docs/books/tutorial/uiswing/concurrency/dispatch.html

作る トム・ホーティン - タックライン ハッピー。もう一度書き直しました

いくつか変更した点があります(行を確認してください) //new コメント)

完全に書き直しました

  • きれいな新しいコンポーネント ファイルに分割 (ImageLoadTest.java) とそれをテストするためのファイル (Tester.java)

オリジナルのポスターコードの改善

  • 親のコンストラクターを呼び出す ImageLoadTest コンストラクター (super())
  • コンポーネントが表示する画像のリストを設定する 2 番目のコンストラクターを提供しました
  • 重要:に呼び出します setPreferredSize() コンストラクター内のコンポーネントの。サイズが設定されていない場合、スイングはコンポーネントをペイントしません。推奨サイズは最大値に基づいています。すべての画像の幅とすべての画像の高さの合計
  • に呼び出します super.paintComponent(g) オーバーライド中 paintComponent()
  • かわった paintComponent 自動的にベースにする yOffset 描画される画像の高さについて

  • EDT上で行われるGUIの初期化

  • を使用して元のコードとして sleep() 画像の読み込みと読み込みに時間がかかる可能性があることを説明するため SwingWorkerが使用されています
  • worker 待ってから新しいタイトルを設定し、画像をロードします
  • 完了すると、 workerdone() 最後にコンポーネントを JFrame そしてそれを表示します。のコンテンツ ペインにコンポーネントを追加しました JFrame で説明されているように Jフレーム アピ。そして、javadocで説明されているように、必要な呼び出しを行いました validate() の上 JFrame 電話した後 add(), として、 JFrame 子が変更したすでに表示されているコンテナです。

javdocからの引用 validate()

検証方法は、コンテナにサブコンポーネントを再度レイアウトするために使用されます。コンテナが表示された後、このコンテナのサブコンポーネントが変更(コンテナに追加または削除された、またはレイアウト関連情報が変更された場合)が呼び出される必要があります。

  • 2 番目のワーカーはさらに待機してから背景色を黒に設定します
  • 使用済み JPanel の基本クラスとして ImageLoadTest 直す setBackground() 私は仕事に取り組むことができませんでした JComponent.

したがって、コンポーネントの推奨サイズを設定していないことと、呼び出していないことが主な問題です validate()JFrame すでに表示されているコンテナに何かを追加した後。

これは機能するはずです

jpanelpaint/ImageLoadTest.java

package jpanelpaint;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
import java.util.List;

public class ImageLoadTest extends JPanel {
  private List<Image> list;

  public ImageLoadTest() {
    super();
  }

  public ImageLoadTest(List<Image> list) {
    this();
    this.list = list;
    int height = 0;
    int width = 0;
    for (Image img : list) {
      height += img.getHeight(this);
      width = img.getWidth(this) > width ? img.getWidth(this) : width;
      setPreferredSize(new Dimension(width, height));
    }
  }

  @Override
  protected void paintComponent(Graphics g) {
    int yOffset=0;
    super.paintComponent(g);
    System.err.println("ImageLoadTest.paintComponent()");
    for(Image img : list) {
      g.drawImage(img, 0, yOffset, null);
      yOffset+=img.getHeight(this);
    }
  }
}

テスター.java

import java.awt.Dimension;
import java.awt.Color;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.SwingUtilities;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import jpanelpaint.ImageLoadTest;

public class Tester {

  private JFrame frame;
  private ImageLoadTest ilt;
  private final int NUMBEROFFILES = 4;
  private List<Image> list;

  //will load the images
  SwingWorker worker = new SwingWorker<List<Image>, Void>() {
    @Override
    public List<Image> doInBackground() throws InterruptedException {
      //sleep at start so user is able to see empty jframe
      Thread.sleep(1000);
      //let Event-Dispatch-Thread (EDT) handle this
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          frame.setTitle("Loading images");
        }
      });
      //sleep again so user is able to see loading has started
      Thread.sleep(1000);
      //loads the images and returns list<image>
      return loadImages();
    }

    @Override
    public void done() {
      //this is run on the EDT anyway
      try {
        //get result from doInBackground
        list = get();
        frame.setTitle("Done loading images");
        ilt = new ImageLoadTest(list);
        frame.getContentPane().add(ilt);
        frame.getContentPane().validate();
        //start second worker of background stuff
        worker2.execute();
      } catch (InterruptedException ignore) {}
      catch (ExecutionException e) {
        String why = null;
        Throwable cause = e.getCause();
        if (cause != null) {
          why = cause.getMessage();
        } else {
          why = e.getMessage();
        }
        System.err.println("Error retrieving file: " + why);
      }
    }
  };

  //just delay a little then set background
  SwingWorker worker2 = new SwingWorker<Object, Void>() {
    @Override
    public List<Image> doInBackground() throws InterruptedException {
      Thread.sleep(1000);
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          frame.setTitle("Setting background");
        }
      });
      Thread.sleep(1000);
      return null;
    }

    @Override
    public void done() {
      ilt.setBackground(Color.BLACK);
      frame.setTitle("Done!");
    }
  };

  public static void main(String args[]) {
    new Tester();
  }

  public Tester() {
    //setupGUI
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        frame = new JFrame("Empty JFrame");
        frame.setSize(new Dimension(1000, 500));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
      }
    });

    //start the swingworker which loads the images
    worker.execute();
  }

  //create image names
  private String[] createImageFileNames(int count){
    String[] fileNames = new String[count];
    for(int i=0; i < count; i++)
      fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp"; 
    return fileNames;
  }

  //load images
  private List<Image> loadImages() {
    List<Image> tmpA = new ArrayList<Image>();
    try {
      for(String name : createImageFileNames(NUMBEROFFILES)){
        System.err.println(name);
        tmpA.add(ImageIO.read(new File(name)));
      }
    } catch (IOException e) { }

    return tmpA;
  }
}

私は「痴女リッチクライアント」の章の最初のカップルを読んでお勧めします。私は長年、Swingを使っていたが、唯一この本を読んだ後、私は最終的に完全にJavaの絵メカニズムが働く方法を正確に理解しました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top