2015-01-07 5 views
0

Я хотел бы иметь объект окна JavaFX в его собственном потоке, который я могу создать и обновить извне (очень часто, 10-20 в секунду). Это окно должно просматривать изображения и обновляться в других классах.Создание окна JavaFX

Основной класс

ImageViewer window = new ImageViewer("Preview"); 
window.show(); 
window.updateFrame(image); 

ImageViewer класс

public class ImageViewer extends Application{ 

private StackPane pane; 
private ImageView imgView; 
private Stage primaryStage; 

public ImageViewer() { 
} 

public void start(Stage primaryStage) { 
    this.primaryStage = primaryStage; 
    pane = new StackPane(); 
    imgView = new ImageView(); 
    pane.getChildren().add(imgView); 
    Scene scene = new Scene(pane); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 

public void updateFrame(Image image) { 
    imgView = new ImageView(image); 
} 

public void show() { Application.launch(); } 

Конструктор, к сожалению, не принимает никаких параметров и ничего не происходит, когда я пытаюсь установить любые значения в этом объекте. Почему это?

+0

Метод 'start (...)' - это то, где должно запускаться ваше приложение. Метод 'Application.launch()' создаст экземпляр вашего подкласса 'Application' для вас. Если вы хотите, чтобы классы, которые вы собираетесь использовать повторно из других частей вашего приложения, они не должны быть подклассами «Приложение». Вероятно, вам нужно будет перестроить это приложение. –

+0

Не возражаете ли вы объяснить больше? Я не могу полностью понять концепцию JavaFX.Как я могу отделить окно (многопоточность) от моего основного приложения для загрузки изображений? – TomTom

+0

Ваш вопрос на самом деле не имеет смысла: как и почти все инструменты пользовательского интерфейса, JavaFX является однопоточным, и все элементы пользовательского интерфейса должны быть доступны из потока приложений FX. Я попытаюсь показать структуру того, как я напишу приложение, которое вы описали. –

ответ

2

Application класса представляет собой целое приложение, и способ его start(...) является методом, когда приложение запускается (вы должны действительно думать о методе start(...) как эквивалент метода main(...) в традиционном приложении Java). Ваш вопрос, кажется, подразумевает, что вы считаете, что класс Application представляет окно; класс Stage представляет собой окно. Однако, насколько я могу судить, вашему приложению в любом случае требуется только одно окно.

При вызове Application.launch() (или в Java-просто запустить JVM указав Application подкласс в качестве основного класса), то FX инструментарий создает экземпляр вашего самого Application класса, начинает FX инструментарий и FX приложений тему, и звонки метод start(...) на примере Application, проходящий через Stage. Вы действительно никогда не должны создавать свой собственный подкласс Application; если вы это сделаете, у вас будет другой экземпляр, из которого был вызван метод start(...).

Как и все инструменты UI, JavaFX является однопоточным. Все операции над «живыми» элементами графика сцены должны быть выполнены в приложении JavaFX Application Thread. Конечно, вы можете иметь фоновый поток, но если им нужно обновить пользовательский интерфейс, они должны организовать обновления в потоке приложения FX, либо путем вызова Platform.runLater(...), либо путем использования API javafx.concurrent. (Фраза «иметь объект окна JavaFX в своем потоке» даже не имеет для меня смысла. В потоках нет объектов, объекты существуют в куче. Нити - это просто абстракция независимой последовательности исполняемых операторов.)

Так что, если вы хотите приложение JavaFX иметь фоновый поток, который периодически обновляет изображение на виде изображения, вы могли бы сделать что-то вроде этого:

// imports omitted 

public class MyImageUpdatingApp extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Label label = new Label("Main application"); 
     BorderPane root = new BorderPane(label); 
     Scene scene = new Scene(root, 600, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     startImageUpdateThread(); 
    } 

    private void startImageUpdateThread() { 
     ImageView imageView = new ImageView(); 
     BorderPane root = new BorderPane(imageView); 
     Scene scene = new Scene(root, 600, 400); 
     Stage imageViewWindow = new Stage() 
     imageViewWindow.setScene(scene); 
     imageViewWindow.show(); 
     final int pause = 50 ; 
     Thread t = new Thread(() -> { 
      while (moreImagesToGet()) { 
       Image image = getNextImage() ; 
       Platform.runLater(() -> imageView.setImage(image)); 
       try { 
        Thread.sleep(pause); 
       } catch (Exception exc) { 
        exc.printStackTrace(); 
        break(); 
       } 
      } 
     }); 
     t.setDaemon(true); // this thread won't prevent application exit 
     t.setName("Image update thread"); 
     t.start(); 
    } 

    // ... 
} 

Очевидно, что вы могли бы учитывать код с startImageUpdateThread в если вы захотите.

Обратите внимание, что этот ответ - это просто показать связь между потоком, генерирующим изображения, и пользовательским интерфейсом. В реальной жизни вам, скорее всего, понадобится еще более сложный код, чтобы сделать это адекватно; маловероятно, что вы можете создавать и отображать изображения достаточно быстро, поэтому вам, вероятно, понадобится BlockingQueue<Image>, чтобы действовать как буфер изображений, с одним потоком, генерирующим изображения, и одним из них.

+0

Теперь я вижу более четко. Благодарю. У меня есть следующие вопросы: если вы хотите использовать JavaFX, GUI всегда станет вашим основным приложением, а не вашей реальной программой? На самом деле мне нужно несколько окон. Мне удалось это сделать, просто добавив еще один этап в «startImageUpdateThread» и создав экземпляр моего класса программы, который создает изображения для их получения. Так ли это должно быть сделано? – TomTom

+0

В основном это правильно. «Этап» - это окно. Чтобы создать больше окон, просто создайте больше 'Stage'. Но вы не должны создавать экземпляр класса 'Application'. «Приложение» является эквивалентом вашего «основного класса»; система просто создает для вас первый этап и передает его в метод 'start (...)' в качестве удобства. Я обновил ответ, чтобы показать создание новых окон. –

Смежные вопросы