Why is paint()/paintComponent() never called?

前端 未结 5 579
轮回少年
轮回少年 2020-12-03 18:23

For the last two days I have tried to understand how Java handles graphics, but have failed miserably at just that. My main problem is understanding exactl

5条回答
  •  隐瞒了意图╮
    2020-12-03 19:12

    To make Tom Hawtin - tackline happy. I rewrote once again

    There are several things I changed (check the lines with the //new comment)

    Rewrote it completely

    • Split into a clean new component file (ImageLoadTest.java) and a file to test it (Tester.java)

    Improvements on original posters code

    • call constructor of parent in ImageLoadTest constructor (super())
    • provided second constructor to set list of images which component should display
    • IMPORTANT: call to setPreferredSize() of component in constructor. If size isn't set swing of course won't paint your component. preferred size is based on max. width of all images and on sum of all image heights
    • call to super.paintComponent(g) in overriden paintComponent()
    • changed paintComponent to automatically base yOffset on height of images being drawn

    • GUI initialization done on EDT

    • as original code based on using sleep() to illustrate loading and loading of images could take a long time SwingWorker's are used
    • worker waits then sets new title and then loads images
    • on completion the worker in done() finally adds the component to the JFrame and displays it. Added component to content pane of JFrame as described in JFrame api. And as described in javadoc made necessary call to validate() on JFrame after calling add(), as the JFrame is an already visible container whichs children changed.

    javdoc citation from validate()

    The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the container has been displayed.

    • second worker just does some more waiting then sets background color to black
    • used JPanel as baseclass for ImageLoadTest to fix setBackground() which I couldn't get to work with JComponent.

    So your main problems where that you didn't set the preferred size of the component and that you did not call validate() on the JFrame after adding something to the already visible container.

    This should work

    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 list;
    
      public ImageLoadTest() {
        super();
      }
    
      public ImageLoadTest(List 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 list;
    
      //will load the images
      SwingWorker worker = new SwingWorker, Void>() {
        @Override
        public List 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
          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() {
        @Override
        public List 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 loadImages() {
        List tmpA = new ArrayList();
        try {
          for(String name : createImageFileNames(NUMBEROFFILES)){
            System.err.println(name);
            tmpA.add(ImageIO.read(new File(name)));
          }
        } catch (IOException e) { }
    
        return tmpA;
      }
    }
    

提交回复
热议问题