为什么paint()/ paintComponent()从未调用过?

oli*_*ren 8 java swing awt paint

在过去的两天里,我试图了解 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;
 }
}
Run Code Online (Sandbox Code Playgroud)

cam*_*ckr 11

paintComponent()在原始代码中不被调用的原因之一是因为组件具有"零大小"并且RepaintManger足够聪明,不会尝试绘制没有大小的东西.

重新排序代码的原因是因为当您将组件添加到框架然后使框架可见时,将调用布局管理器来布局组件.默认情况下,一个框架使用BorderLayout,默认情况下,一个组件被添加到BorderLayout的中心,该组件会给予组件可用的所有空间,以便绘制它.

但是,您将内容窗格的布局管理器更改为FlowLayout,您仍然会遇到问题,因为FlowLayout会考虑组件的首选大小为零.

因此,您真正需要做的是为您的组件分配首选大小,以便布局管理员可以完成他们的工作.


Chr*_* B. 5

这里的一个主要问题是您没有在事件调度线程(EDT)上更新您的 swing 组件。尝试将所有代码包装在 main 方法中,如下所示:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            // swing code here...             
        }
    });
Run Code Online (Sandbox Code Playgroud)

另外:在将框架设置为可见之前,将 ImageLoadTest 添加到框架中。这是基于对代码的快速粗略阅读——我将进一步阅读它,看看我还能找到什么。

编辑:

遵循我上面最初的建议,并将您的 main 方法简化为如下所示,并且您的 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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

此外,我还会阅读有关使用计时器执行动画、一般 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


oli*_*ren 3

这些是导致其无法工作的原始代码的主要问题:

  1. 在 add() 操作后不调用 validate()
  2. 没有设置组件的首选大小。
  3. 覆盖 super.paintComponent() 时不调用它(这使得 setBackground() 调用不起作用)
  4. 我需要继承 JPanel 才能绘制它。Component 和 JComponent 都不足以让 setBackground() 调用正常工作,即使修复了第 3 点也是如此。

完成上述操作后,调用 PaintComponent 或 Paint 方法实际上并不重要,只要我记得在开始时调用超级构造函数,两者似乎都可以工作。

此信息是根据 @jitter、@tackline 和 @camickr 撰写的内容汇总的,非常值得称赞!

PS 不知道回答你自己的问题是否被认为是不好的形式,但由于我需要的信息是由几个答案组合而成的,我认为最好的方法是更新其他答案并写出这样的总结。