2016-11-02 8 views
1

приведенный ниже код представляет собой реализацию заставки для небольшого приложения Java, которое я разработал с помощью Eclipse. Заставка отлично работает на ПК, но не на MAC. В MAC OSX сначала появляется кадр с серой областью в течение 2 секунд, а затем изображение появляется в течение оставшихся 4 секунд. Изображение должно появляться сразу и в течение 4 секунд. У вас есть идея, почему есть задержка до появления изображения на MAC, пока все работает хорошо на ПК? PS: Я развернул приложение как исполняемый Jar, и я использую Java 8 на всех компьютерах. Спасибо.Java-заставка не работает на Mac OSX, но работает на ПК

public static void main(String[] args) 
{ 
    SplashScreen splSplashScreen = new SplashScreen(); 
    //Main window 
    FenetrePrincipale fenetrePrincipale = new FenetrePrincipale(); 
} 
public class SplashScreen extends JWindow 
{ 
    /** 
    * Numéro de série 
    */ 
    private static final long serialVersionUID = 1592663893301307318L; 

    private final static long TEMP_AFFICHAGE = 4000; 

    /** 
    * Constructeur par initialisation 
    * @param p_Frame Frame 
    * @param p_TempsAffichage Temps d'affichage en millisecondes 
    */ 
    public SplashScreen() 
    { 
     super(new Frame()); 
     JLabel lblImage = new JLabel(new ImageIcon(this.getClass().getResource("/res/ui/splashScreen.jpg"))); 

     Container container = this.getContentPane(); 
     container.add(lblImage, BorderLayout.CENTER); 
     pack(); 

     Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
     Dimension labelSize = lblImage.getPreferredSize(); 
     this.setLocation(screenSize.width/2 - (labelSize.width/2), screenSize.height/2 - (labelSize.height/2)); 

     this.setVisible(true); 

     try 
     { 
      Thread.sleep(TEMP_AFFICHAGE); 
     } 
     catch (InterruptedException ex) 
     { 
      ApplicationLogger.getInstance().severe(ex.getLocalizedMessage()); 
     } 
     finally 
     { 
      this.setVisible(false); 
     } 
    } 
} 
+0

'Thread.sleep()' заставляет Java-приложение прекратить обработку сообщений; что означает, что пользовательский интерфейс не обновляется. Следуйте посылке в [этом ответе] (http://stackoverflow.com/questions/16288303/best-example-for-programmatically-creating-splashscreen-with-text), который должен помочь вам в надлежащем создании рабочего. – Petesh

+0

Но изображение появляется до конца Thread.sleep(). И Thread.sleep() не должен останавливать загрузку изображения, потому что изображение загружается до Thread.sleep() (this.setVisible (true);). – user3787028

+0

Он останавливает репликации, что и вызывает проблему. Когда вы блокируете поток пользовательского интерфейса, это происходит. Решение состоит в том, чтобы: * не блокировать поток пользовательского интерфейса * – Petesh

ответ

2

Редактировать Это полностью отличается от оригинального ответа; Я оставляю оригинальный ответ ниже.

Похоже, что первоначальный рендеринг JLabel является медленным на OSX - удаление всех сон по-прежнему оставляет меня с паузой в 2 секунды, в то время как java отображает метку. Поэтому мы меняем правила.

Сначала мы создаем класс JPanel, который принимает буферное изображение:

class ImgPanel extends JPanel { 
    private BufferedImage img; 

    public ImgPanel(BufferedImage img) { 
     this.img = img; 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(img.getWidth(), img.getHeight()); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.drawImage(img, 0, 0, null); 
    } 
} 

Затем мы изменяем конструктор экрана-заставки, как так:

public SplashScreen() 
{ 
    BufferedImage img = null; 
    try { 
     img = ImageIO.read(this.getClass().getResource("/res/ui/splashScreen.jpg")); 
    } catch (Exception ex) { 
    } 

    ImgPanel panel = new ImgPanel(img); 
    Container container = this.getContentPane(); 
    container.add(panel); 
    pack(); 

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 
    this.setLocation(screenSize.width/2 - (img.getWidth()/2), screenSize.height/2 - (img.getHeight()/2)); 

    this.setVisible(true); 
} 

Это делает изображение как только появится панель без паузы.

Примечание - я удалил весь код сна, чтобы уменьшить путаницу - логика будет лучше захваченной в отдельном SwingWorker выполнить шкура заставок и отображение главного экрана:

class worker extends SwingWorker<String, Object> { 
    private final static long TEMP_AFFICHAGE = 4000; 
    private SplashScreen splash; 
    private FenetrePrincipale principale; 

    public worker(SplashScreen splash, FenetrePrincipale principale) { 
     this.splash = splash; 
     this.principale = principale; 
     this.splash.setVisible(true); 
    } 

    @Override 
    public String doInBackground() { 
     try 
     { 
      Thread.sleep(TEMP_AFFICHAGE); 
     } 
     catch (InterruptedException ex) 
     { 
      ApplicationLogger.getInstance().severe(ex.getLocalizedMessage()); 
     } 
     return ""; 
    } 

    @Override 
    protected void done() { 
     splash.setVisible(false); 
     principale.setVisible(true); 
    } 
}; 

Тогда основной код выглядит следующим образом:

public static void main(String[] args) 
{ 
    SplashScreen splSplashScreen = new SplashScreen(); 
    //Main window 
    FenetrePrincipale fenetrePrincipale = new FenetrePrincipale(); 
    worker w = new worker(splSplashScreen, fenetrePrincipale); 
    w.execute(); 
} 

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

Хорошо, простой пример того, чтобы поместить сон от графического интерфейса потока, используя код брызговик - этот код приходит после this.setVisible(true), и заменяет попытку {} поймать {} наконец {} пункт:

this.setVisible(true); 

    worker do_work = new worker(this); 
    do_work.execute(); 
} 

class worker extends SwingWorker<String, Object> { 
    private SplashScreen parent; 

    public worker(SplashScreen parent) { 
     this.parent = parent; 
    } 

    @Override 
    public String doInBackground() { 
     try 
     { 
      Thread.sleep(TEMP_AFFICHAGE); 
     } 
     catch (InterruptedException ex) 
     { 
      ApplicationLogger.getInstance().severe(ex.getLocalizedMessage()); 
     } 
     return ""; 
    } 

    @Override 
    protected void done() { 
     parent.setVisible(false); 
    } 
}; 

Я просто создаю SwingWorker, который делает сон как doWorkInBackground, и как только это завершено, он закрывает родительский фрейм, который является заставкой.

+0

Как написано, главное окно можно открыть, пока экран заставки все еще отображается. Если вы хотите отложить главное окно от видимости до тех пор, пока экран заставки не исчезнет, ​​вам нужно будет поместить вызов в «сделанную» часть SwingWorker. Это можно относительно легко обрабатывать, перемещая SwingWorker в основной класс, чтобы он имел ссылку как на заставку, так и на главное окно; позволяя ему управлять открытием одного и другого. – Petesh

+0

Я внедрил свой класс SwingWorker именно так, как вы сказали, и никакого улучшения. Это не решило проблему вообще на Mac OSX (но она работает на ПК). Есть еще серое окно в течение примерно 2 секунд после того, как я дважды щелкнул файл Jar, тогда изображение появится для оставшихся 4 секунд Thread.Sleep(). Поэтому проблема заключается не в том, что я блокирую поток пользовательского интерфейса (в конце концов, все решения работают на ПК). Это не работает на Mac OSX. Если у вас есть другие идеи, отправьте сообщение! Спасибо! – user3787028

+0

Начальное серое окно - это пока JVM отображает изображение в JLabel. В этом случае это не имеет никакого отношения к потоку сна. Я изменю свой ответ, чтобы использовать что-то более легкое, как jpanel. – Petesh