2010-12-09 2 views
4

Я пытаюсь создать программу на Java, которая будет отображать множество изображений один за другим, изменяя размер кадра для каждого из них. Я простирающийся JPanel для отображения изображения, как это:Java ждет, когда компонент будет окрашен

public class ImagePanel extends JPanel{ 

String filename; 
Image image; 
boolean loaded = false; 

ImagePanel(){} 

ImagePanel(String filename){ 
    loadImage(filename); 
} 

public void paintComponent(Graphics g){ 
    super.paintComponent(g); 
    if(image != null && loaded){ 
     g.drawImage(image, 0, 0, this); 
    }else{ 
     g.drawString("Image read error", 10, getHeight() - 10); 
    } 
} 

public void loadImage(String filename){ 
    loaded = false;   
    ImageIcon icon = new ImageIcon(filename); 
    image = icon.getImage(); 
    int w = image.getWidth(this); 
    int h = image.getHeight(this); 
    if(w != -1 && w != 0 && h != -1 && h != 0){ 
     setPreferredSize(new Dimension(w, h)); 
     loaded = true; 
    }else{ 
     setPreferredSize(new Dimension(300, 300)); 
    } 
} 

}

Тогда в потоке событий, что я делаю основную работу:

 SwingUtilities.invokeLater(new Runnable(){ 

     @Override 
     public void run(){ 
      createGUI(); 
     } 
    }); 

В createGUI() Я пройдя через набор изображений:

 ImagePanel imgPan = new ImagePanel(); 
    add(imgPan); 

    for(File file : files){ 
     if(file.isFile()){ 
      System.out.println(file.getAbsolutePath()); 

      imgPan.loadImage(file.getAbsolutePath()); 
      pack(); 

      try { 
       Thread.sleep(500); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    } 

Проблема в том, что моя программа выполняет изменение размера p потому что изображения загружаются правильно, но ничего не отображает. Если я показываю только одно изображение, оно работает и работает для последнего изображения. Я думаю, проблема заключается в том, что Thread.sleep() вызывается до завершения рисования изображения.

Как я могу подождать, пока моя ImagePanel закончит рисовать и начнет ждать после этого? Или есть другой способ решить проблему?

Спасибо! Leonty

ответ

4

Весь ваш код выполняется в разделе «Диспетчер событий». Это фактически заставляет все взаимодействие с пользователем спать, так как Thread Dispatch Thread отвечает за все взаимодействие с пользователем - как вход (события), так и вывод (покраска).

Вам нужно, чтобы ваше ожидание произошло за пределами EDT. Вы должны знать, как выполнять события на и вне EDT. Вы делаете это, создавая новый Runnable, а затем либо вызываете new Thread(runnable), чтобы выполнить его с EDT, либо SwingUtilities.invokeLater(runnable), чтобы выполнить его на EDT. Все взаимодействие с компонентами Swing должно происходить на EDT, поскольку объекты Swing не являются потокобезопасными. Все сон, ожидание, доступ к файлам, доступ к сети, доступ к базе данных или что-либо еще, что может блокироваться в течение неопределенных периодов времени, должно происходить с EDT.

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

+0

Спасибо! Это поставило меня на правильный путь! Теперь я выполняю код в основном потоке, и все операции теперь синхронны, поэтому ожидание происходит только после завершения рисования. – Leonti 2010-12-10 23:47:58

1

Вместо того чтобы сделать поток сна, используйте таймер и начинайте следующее изображение в качестве события.

+0

Я попробовал, и она работала, но мне нужно было использовать пакет(), чтобы изменить размер окна для каждого изображения, и я была та же проблема - мне нужно было знать, когда закончится рисование, чтобы называть «pack()». – Leonti 2010-12-10 23:51:33

1

Похоже, что вы хотите, чтобы изображения отображались один за другим, когда они загружаются (то есть, как на веб-странице), это правильно? Если это так, вы не получите этого эффекта с вашим текущим кодом, потому что ваш пользовательский интерфейс не будет обновляться до загрузки всех изображений, это связано с тем, что вы загружаете изображения на EDT (Thread Dispatch Thread), который является тем же потоком, сделаю картину. Покраска происходит «когда есть время», что в этом случае означает, что после загрузки всех изображений.

Чтобы решить проблему, я предлагаю вам создать вложенный класс SwingWorker как:

public class MyImageLoader extends SwingWorker<Void, String> 
{ 
    // Is executed in background thread, EDT can meanwhile load and paint images 
    @Override 
    protected Void doInBackground() throws Exception 
    { 
     for(File file : files) 
     { 
      if(file.isFile()) // Maybe some more check to see if it's an image 
      { 
       publish(file.getAbsolutePath()); 
       Thread.sleep(500); 
      } 
     } 
    } 

    // Executed on EDT 
    @Override 
    protected void process(List<String> filePaths) 
    { 
     for(String path : filePaths) 
     { 
      // Load ImageIcon to UI 
     } 
    } 
} 
Смежные вопросы