Почему краска ()/paintComponent (), никогда не звонил?

NTP является определенно способом пойти. В основном "выпустил-забыл", пока Вы позволяете ему брандмауэр на Вашем локальном ведущем устройстве (который обычно является машиной брандмауэра или маршрутизатора.)

8
задан oligofren 4 November 2009 в 19:53
поделиться

5 ответов

Это были основные проблемы с исходным кодом, из-за которых он не работал:

  1. не вызывается validate () после операции add ()
  2. не устанавливается предпочтительный размер составная часть.
  3. не вызывается super.paintComponent () при его переопределении (это сделало setBackground () не работает)
  4. Мне нужно было унаследовать от JPanel, чтобы он рисовался. Ни Component, ни JComponent не было достаточно для работы вызова setBackground (), даже при исправлении точки 3.

После выполнения вышеизложенного, действительно не имело значения, вызывается ли метод paintComponent или paint, оба, казалось, работают до тех пор, пока Я не забыл вызвать суперконструктор в самом начале.

Эта информация была собрана из того, что написали @jitter, @tackline и @camickr, так что большое спасибо!

PS Не знаю, считается ли ответ на свой вопрос плохим тоном , но поскольку информация, которая мне нужна, была собрана из нескольких ответов, я подумал, что лучший способ - это обновить другие ответы и написать такую ​​сумму.

3
ответ дан 5 December 2019 в 06:53
поделиться

One of the reasons the paintComponent() doesn't get invoked in the original code is because the component has a "zero size" and the RepaintManger is smart enough not to try and paint something with no size.

The reason the reordering of the code works is because when you add the component to the frame and then make the frame visible the layout manager is invoked to layout the component. By default a frame uses a BorderLayout and by default a component is added to the center of the BorderLayout which happens give all the space available to the component so it gets painted.

However, you change the layout manager of the content pane to be a FlowLayout, you would still have a problem because a FlowLayout respects the preferred size of the component which is zero.

So what you really need to do is assign a preferred size to you your component so layout managers can do their job.

11
ответ дан 5 December 2019 в 06:53
поделиться

Одна из основных проблем заключается в том, что вы не обновляете компоненты Swing в потоке отправки событий (EDT) . Попробуйте обернуть весь код вашего основного метода следующим образом:

    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

4
ответ дан 5 December 2019 в 06:53
поделиться

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 контейнер был отображен.

  • второй рабочий просто еще немного подождал, затем установил черный цвет фона
  • использовал 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);
    }
  }
}

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;
  }
}
4
ответ дан 5 December 2019 в 06:53
поделиться

Я рекомендую прочитать первую пару глав «Filthy Rich Clients». Я использовал Swing в течение многих лет, но только после прочтения этой книги я наконец полностью понял, как работает механизм рисования в Java.

2
ответ дан 5 December 2019 в 06:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: