【问题标题】:why calling repaint in this code?为什么在这段代码中调用重绘?
【发布时间】:2012-02-02 23:47:34
【问题描述】:

如果你在内容窗格中添加一个 jpanel 实例,paintComponent 方法就会被调用,对吧?

content_pane.add (fDrawingPanel);

那么为什么要在run() 方法的第一行调用“repaint”呢? (它说“绘制加载消息,但它应该已经绘制,因为之前调用了paintComponent,并且一旦fShow 为真,我们不会将其设置回假,所以我认为这段代码是,应该被调用一次):

public class MediaTrackApplet extends JApplet
                       implements Runnable
{
  // Need a reference to the panel for the
  // thread loop.
  DrawingPanel fDrawingPanel;

  // Parameters to track the image
  MediaTracker fTracker;
  Image fImg;
  int fImageNum = 0;
  boolean fShow = false;
  String fMessage ="Loading...";

  /** Use a MediaTracker to load an image.**/
  public void init () {
    Container content_pane = getContentPane ();

    // Create an instance of DrawingPanel
    fDrawingPanel = new DrawingPanel (this);

    // Add the DrawingPanel to the contentPane.
    content_pane.add (fDrawingPanel);

    // Get image and monitor its loading.
    fImg = getImage (getCodeBase (), "m20.gif.jpg" );
    fTracker = new MediaTracker (this);

    // Pass the image reference and an ID number.
    fTracker.addImage (fImg, fImageNum);
  } // init

  /** If the image not yet loaded, run the thread
    * so the run() will monitor the image loading.
   **/
  public void start () {
    if (!fTracker.checkID (fImageNum) ) {
        Thread thread = new Thread (this);
        thread.start ();
    } else
        // Unloading/reloading web page can will leave
        // checkID true but fShow will be false.
        fShow = true;
  } // start

  /** Use a thread to wait for the image to load 
    * before painting it.
   **/
  public void run ()  {
    // Paint the loading message
    repaint ();
    // The wait for the image to finish loading
    try {
      fTracker.waitForID (fImageNum );
    } catch (InterruptedException e) {}

    // Check if there was a loading error
    if (fTracker.isErrorID (fImageNum ))
        fMessage= "Error";
    else
        fShow = true;
    // Repaint with the image now if it loaded OK
    repaint ();
  } // run

}// class MediaTrackApplet


/** This JPanel subclass draws an image on the panel if
  * the image is loaded. Otherwise, it draws a text message.
 **/
class DrawingPanel extends JPanel {
  MediaTrackApplet parent = null;

  DrawingPanel (MediaTrackApplet parent) {
    this.parent = parent;
  }// ctor

  public void paintComponent (Graphics g) {
    super.paintComponent (g);

    // Add your drawing instructions here
    if (parent.fShow)
        g.drawImage (parent.fImg,10,10,this);
    else
        g.drawString (parent.fMessage, 10,10);
  } // paintComponent

} // class DrawingPanel

谢谢

【问题讨论】:

  • 为什么不尝试评论重绘行并尝试运行它并查看结果而不是在这里提问?
  • 或者,如果您使用的是 IDE,您可以在绘制代码中设置断点并在调试模式下运行它
  • 自从引入ImageIO 类以来,大部分代码都变得多余了。它在加载图像时会阻塞,因此不需要MediaTracker
  • 另见Initial Threads
  • Applet.getImage(URL) 方法是异步的(不是阻塞),因此需要 MediaTracker 来检查图像的加载。 ImageIO.read(File/URL/InputStream) 确实 阻止。当方法完成时,它要么返回一个有效的、完整的图像,要么抛出一个Exception。因此ImageIO 加载的图像不需要跟踪器。我相信ImageIcon 有自己的媒体跟踪器,但如果您不需要ImageIcon,请不要创建一个 - 只需改用ImageIO

标签: java swing applet repaint jcomponent


【解决方案1】:

你指的是EDT吗?

是的。这个古老但过时的例子来自一个早于我们现代理解的时代,即应该event dispatch thread 上构造和操作Swing GUI 对象。 repaint() 的初始调用具有在EventQueue 上发布新Runnable 的效果,同时允许后台线程完成加载图像以预期后续repaint()。另请参阅Memory Consistency Properties 和相关的example

【讨论】:

  • 但是paintComponent 已经在EDT 中绘制了图形,不是吗?在代码中,当我们将面板添加到内容窗格中时,我们默认添加加载文本,然后:调用第一次重绘以加载(再次)加载消息(这是我不明白的:这个双重调用加载图像之前的paintComponent),然后才:我们使用waitForID加载图像。
  • 示例同步不正确,应该弃用。看起来它应该在图像加载时显示“正在加载”消息并随后绘制图像或错误消息。
  • mmh 好吧,所以我以为我没有理解第一次重绘的含义,但看起来这不是强制性的:我只能在run() 方法中使用第二次重绘对吗?跨度>
  • 否;至少,fShow 上存在数据竞争。该程序的运行时行为可能因一台机器而异。 @Andrew Thompson 的 cmets 提出了一种更可靠的方法。如果需要在后台加载图片,请使用SwingWorker
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2011-05-27
  • 1970-01-01
  • 2018-10-18
  • 2016-08-02
  • 2016-09-17
  • 2017-05-19
相关资源
最近更新 更多