Monday, October 8, 2018

Developing a simple tray application in JavaFx



      some desktop applications need to be active for a long time or running in the background waiting for some event to occur, like a mailing for example. tray application is the best choice for this type  of situations.

in javafx we need some help from the AWT library because the javafx doesn't have the equivalent of java.awt.SystemTray yet.

what you see below is the the class responsible for the creation of the tray menu. I think it's
self-explanatory.

import java.awt.AWTException;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.stage.Stage;

public class TrayManager {
  public TrayManager() {
     }
     
     
     private TrayIcon trayIcon;
     private Stage stage;
     
     public void createTrayIcon(final Stage stage) {
                 this.stage = stage;
                 
   if (SystemTray.isSupported()) {
    // get the SystemTray instance
    SystemTray tray = SystemTray.getSystemTray();
    // load an image
    java.awt.Image image = Toolkit.getDefaultToolkit().getImage(TrayManager.class.getResource("chart.png"));   
    // create a action listener to listen for default action executed on the tray icon
    final ActionListener closeListener = (java.awt.event.ActionEvent e) -> {
                             System.exit(0);
                         };

    ActionListener showListener = (java.awt.event.ActionEvent e) -> {
                             Platform.runLater(() -> {
                                 this.stage.show();                                
                             });
                         };

    // create a popup menu
    PopupMenu popup = new PopupMenu();

    MenuItem showItem = new MenuItem("Show");
    showItem.addActionListener(showListener);
    popup.add(showItem);

    MenuItem closeItem = new MenuItem("Exit");
    closeItem.addActionListener(closeListener);
    popup.add(closeItem);

    trayIcon = new TrayIcon(image, "tray app demo", popup);   
    
                     try {
                         tray.add(trayIcon);                        
                         trayIcon.displayMessage("note", "Application is active", TrayIcon.MessageType.INFO);
                     } catch (AWTException ex) {
                         Logger.getLogger(TrayManager.class.getName()).log(Level.SEVERE, null, ex);
                     }

   }
  }
     
     public void showProgramIsMinimizedMsg() {
   trayIcon.displayMessage("note", "application is mimimized", TrayIcon.MessageType.INFO);
  }
}
we can now create a basic Fxml application that uses the code above :

public class Main extends Application {
 TrayManager trayManager = new TrayManager();
  
 @Override
 public void start(Stage primaryStage) {
  try {
   BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Main.fxml"));
   Scene scene = new Scene(root,400,400);
   scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
   primaryStage.setScene(scene);
   
   
   Platform.setImplicitExit(false);
   
   primaryStage.setOnCloseRequest((WindowEvent event) -> {
    primaryStage.hide();
             event.consume();
         });
   
   primaryStage.setOnHidden((WindowEvent event) -> {
             trayManager.showProgramIsMinimizedMsg();
         });
   
   
   
   
   trayManager.createTrayIcon(primaryStage);
   
   
         
  } catch(Exception e) {
   e.printStackTrace();
  }
 }
 
 public static void main(String[] args) {
  launch(args);
 }
}





here is the result :

note :

the demo application written in eclipse photon can be downloaded from this link :


Tuesday, April 24, 2018

Using multiples FXML files in a javafx application

In this post we assume that you have the knowledge necessary for building your user interface with the JavaFX SceneBuilder.

Usually, one FXMl file represent one screen in the user interface and practically any decent application has more than one.







So how to switch between mutiples fxml files ?


Remember that FXML files are loaded into JavaFX applications by the JavaFX runtime using the FXML Loader class and the result is always a Java object, usually a node such as a Group or a Pane.

So for this purpose we will use a screen controller that holds all of the instances of the fxml files loaded. And every fxml controller will point the instance of that controller.
The screen controller will give the appropriate root to the scene when needed.


public class Controller {
    Pane                     container;
    Map<String, Pane>        screens;  
    public Controller(Pane container) {
        this.container = container;
        screens = new HashMap<>();
    }      

    public void switchContent(String fxml) {            
       container.getChildren().clear();                
       container.getChildren().add(getContent(fxml)); 
    }

    private Pane getContent(String fxml) {        
        if (!screens.containsKey(fxml)) {
            Parent node = loadContent(fxml);
            screens.put(fxml,(Pane) node);
        }        
        return screens.get(fxml);
    }

    private Parent loadContent(String fxml) {
        String path = String.format("%s.fxml", fxml);
        FXMLLoader loader = new FXMLLoader();
        loader.setBuilderFactory(new JavaFXBuilderFactory());
        loader.setLocation(this.getClass().getResource(path));
        Parent page = null;
        try (InputStream in = this.getClass().getResourceAsStream(path)) {
            page = loader.load(in);
            ((Managed) loader.getController()).setScreensController(this);
        } catch (IOException ex) {
            ex.printStackTrace();
        }                     
        return page;
    }         
}