문제

지난 이틀 동안 나는 노력했다 이해하다 Java가 그래픽을 처리하는 방법이지만 비참하게 실패했습니다. 내 주요 문제는 Paint () (또는 최신 PaintComponent ())가 호출되는 방법과시기를 정확하게 이해하는 것입니다.

다음 코드에서 물건이 생성되는 시점을 확인하기 위해 만든 코드에서는 PaintComponent ()가 수동으로 전화를 걸거나 jframe.paintall ()/jframe.paintcomponents ()로 전화를 걸지 않는 한 절대 호출되지 않습니다.

나는 Paint () 메소드를 PaintComponent ()에 이름을 바꾸면서 (Repaint ()에서도 불려지 는데도 불구하고 운이 없다는 내 문제를 해결하기를 희망합니다.

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 ()를 호출하지 않음 (이로 인해 work가 작동하지 않음)
  4. 페인트 칠을하려면 jpanel에서 물려 나야했습니다. 포인트 3을 고치는 경우에도 구성 요소 나 jcomponent가 work to work에 충분하지 않았습니다.

위의 작업을 수행 한 후에는 PaintComponent 또는 Paint 메소드를 호출하는 것이 중요하지 않았으며, 처음에는 슈퍼 생성자를 호출하는 것을 기억하는 한 둘 다 작동하는 것처럼 보였습니다.

이 정보는 @jitter, @tackline 및 @camickr이 쓴 것, So Big Kudos에서 조립되었습니다!

추신 : 자신의 질문에 대답하는 것이 나쁜 형태로 간주되는지는 모르겠지만, 필요한 정보가 여러 답변에서 조립되었으므로 가장 좋은 방법은 다른 답변을 상승시키고 이와 같은 요약을 작성하는 것이라고 생각했습니다.

다른 팁

원래 코드에서 PaintComponent ()가 호출되지 않는 이유 중 하나는 구성 요소에 "제로 크기"가 있고 Repaintmanger가 크기없이 무언가를 시도하지 않을 정도로 똑똑하기 때문입니다.

코드의 재정렬이 작동하는 이유는 구성 요소를 프레임에 추가 한 다음 프레임을 보이게 할 때 레이아웃 관리자가 구성 요소를 레이아웃하기 위해 호출되기 때문입니다. 기본적으로 프레임은 경계선을 사용하고 기본적으로 구성 요소가 경계선의 중심에 추가되어 구성 요소가 사용할 수있는 모든 공간을 제공하여 페인트를 칠할 수 있습니다.

그러나 컨텐츠 창의 레이아웃 관리자를 FlowLayout으로 변경하면 FlowLayout이 0 인 구성 요소의 선호하는 크기를 존중하기 때문에 여전히 문제가 있습니다.

따라서 실제로해야 할 일은 레이아웃 관리자가 작업을 수행 할 수 있도록 구성 요소에 선호하는 크기를 할당하는 것입니다.

여기서 주요 문제 중 하나는 스윙 구성 요소를 업데이트하지 않는다는 것입니다. 이벤트 디스패치 스레드 (EDT). 다음의 주요 메소드에서 모든 코드를 래핑하십시오.

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

또한 : 프레임을 표시하기 전에 프레임에 ImageEloadtest를 추가하십시오. 이것은 코드를 빠르게 읽은 내용을 기반으로합니다. 더 읽고 다른 것을 찾을 수있는 것을 볼 것입니다.

편집하다:

위의 원래 조언을 따르고 주요 방법을 단순화하여 다음과 같이 보이면 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);
        }
    });
}

또한 타이머를 사용하여 애니메이션을 수행하고 일반적인 스윙 이벤트 디스패치 및 다양한 페인트 방법을 어떻게/언제 상체하는지 읽었습니다.

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

만들다 Tom Hawtin- 태클 라인 행복하다. 다시 한 번 다시 작성했습니다

내가 변경 한 몇 가지가 있습니다 (라인을 확인하십시오. //new 논평)

완전히 다시 작성하십시오

  • 깨끗한 새 구성 요소 파일로 분할 (ImageLoadTest.java) 및 테스트 할 파일 (Tester.java)

원래 포스터 코드의 개선

  • 부모의 호출 생성자 ImageLoadTest 생성자 (super())
  • 구성 요소가 표시 해야하는 이미지 목록을 설정하도록 두 번째 생성자 제공
  • 중요 : 전화로 setPreferredSize() 생성자의 구성 요소. 크기가 설정되지 않으면 스윙이 물론 구성 요소를 페인트하지 않습니다. 우선 크기는 Max를 기반으로합니다. 모든 이미지의 너비 및 모든 이미지 높이의 합계
  • ~에게 전화 해 super.paintComponent(g) 재정의 paintComponent()
  • 변경 paintComponent 자동으로베이스 yOffset 그려진 이미지의 높이

  • EDT에서 GUI 초기화가 완료되었습니다

  • 사용을 기반으로 원래 코드로 sleep() 이미지의 로딩 및 로딩을 설명하는 데 시간이 오래 걸릴 수 있습니다. SwingWorker사용됩니다
  • worker 대기는 새 제목을 설정 한 다음 이미지를로드합니다
  • 완료시 worker 안에 done() 마지막으로 구성 요소를 추가합니다 JFrame 그리고 그것을 표시합니다. 콘텐츠 창에 구성 요소가 추가되었습니다 JFrame 설명대로 JFrame API. Javadoc에 설명 된대로 필요한 전화를 걸었습니다 validate() ~에 JFrame 전화 후 add(),로 JFrame 아이들이 바꾸는 이미 눈에 띄는 용기입니다.

JAVDOC 인용 validate()

Validate 방법은 컨테이너가 하위 구성 요소를 다시 배치하는 데 사용됩니다. 컨테이너가 표시된 후이 컨테이너의 하위 구성 요소가 수정되거나 컨테이너에 추가되거나 레이아웃 관련 정보가 변경됨)가 호출되어야합니다.

  • 두 번째 작업자는 더 많은 대기를하고 배경색을 검은 색으로 설정합니다.
  • 사용된 JPanel 베이스 클래스로 ImageLoadTest 고치다 setBackground() 함께 일할 수 없었습니다 JComponent.

따라서 구성 요소의 선호하는 크기를 설정하지 않고 전화하지 않은 주요 문제 validate()JFrame 이미 보이는 용기에 무언가를 추가 한 후.

이것은 작동해야합니다

jpanelpaint/imageeloadtest.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);
    }
  }
}

Tester.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