3

Is there way to create status menu with JavaFX? Documentation of JavaFX seems doesn't have anything similar. enter image description here

Left side menu is pretty simple:

MenuBar menuBar = new MenuBar();
menuBar.useSystemMenuBarProperty().set(true);

Menu menu = new Menu("java");
MenuItem item = new MenuItem("Test");
menu.getItems().add(item);
menuBar.getMenus().add(menu);

BorderPane borderPane = new BorderPane();
borderPane.setTop(menuBar);
primaryStage.setScene(new Scene(borderPane));
primaryStage.show();
eleven
  • 6,779
  • 2
  • 32
  • 52
  • Not having given any specifics, the short answer would be "yes, there is a way". Showing how such a thing would be done is likely too broad for this site. However, that image looks like it could be done with an `HBox` which contains the various status icons/controls. The _ControlsFX_ library has a `StatusBar` control which may be of use. – Slaw Dec 17 '18 at 19:59
  • Not sure actually how I can be more specific. It's not about visual component (like `HBox`), it's a distinctive MacOS element which could be built probably with specific system API (https://developer.apple.com/documentation/appkit/nsstatusbar). So I'm interested whether `JavaFX` handles this API. Just an example is Bitbar: https://github.com/matryer/bitbar – eleven Dec 18 '18 at 10:47
  • Ah, I understand now. There's no standard public API for JavaFX that can do this. I'm also not aware of any JavaFX-specific libraries that can do this either. You can look at this [curated list](https://github.com/mhrimaz/AwesomeJavaFX) of JavaFX related things to see if anything fits your needs. I'm not sure if it's the same thing but there's also [`java.awt.SystemTray`](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/SystemTray.html). – Slaw Dec 18 '18 at 11:11
  • @Slaw ok, thanks. That's what I actually expected. If you add an answer I'll accept it. – eleven Dec 18 '18 at 11:33
  • I agree with @Slaw, but its not clear if you want to modify the Mac menu bar or create your own; here's a `SystemTray` [example](https://stackoverflow.com/a/2935521/230513); see also [*How to make an OS X menubar in JavaFX*](https://stackoverflow.com/q/22569046/230513). – trashgod Dec 18 '18 at 12:33
  • @trashgod that works! Thanks. I needed to create it. – eleven Dec 19 '18 at 10:37
  • @eleven: `SystemTray`? This may be a [duplicate](https://stackoverflow.com/q/12571329/230513), but it's not MacOS specific. Can you can [answer your own question](http://meta.stackoverflow.com/q/17463/163188)? – trashgod Dec 19 '18 at 17:26
  • @trashgod done. – eleven Dec 27 '18 at 11:53

1 Answers1

3

So, there is way to show menu with java.awt.SystemTray:

public static void showMenu(Image trayImage, String... items) {

    if (!java.awt.SystemTray.isSupported())
        throw new UnsupportedOperationException("No system tray support, application exiting.");

    java.awt.Toolkit.getDefaultToolkit();

    java.awt.SystemTray tray = java.awt.SystemTray.getSystemTray();
    java.awt.TrayIcon trayIcon = new java.awt.TrayIcon(trayImage);
    java.awt.PopupMenu rootMenu = new java.awt.PopupMenu();

    for (String item : items) rootMenu.add(new MenuItem(item));

    trayIcon.setPopupMenu(rootMenu);

    try {
        tray.add(trayIcon);
    } catch (Throwable e) {
        throw new RuntimeException("Unable to init system tray");
    }
}

SystemTray supports only image as root item, but there is way to convert text into image:

static BufferedImage textToImage(String text) {
    return textToImage(text, java.awt.Font.decode(null), 13);
}

static BufferedImage textToImage(String Text, Font font, float size) {
    font = font.deriveFont(size);

    FontRenderContext frc = new FontRenderContext(null, true, true);

    LineMetrics lm = font.getLineMetrics(Text, frc);
    Rectangle2D r2d = font.getStringBounds(Text, frc);
    BufferedImage img = new BufferedImage((int) Math.ceil(r2d.getWidth()), (int) Math.ceil(r2d.getHeight()), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2d = img.createGraphics();
    g2d.setRenderingHints(RenderingProperties);
    g2d.setBackground(new Color(0, 0, 0, 0));
    g2d.setColor(Color.BLACK);

    g2d.clearRect(0, 0, img.getWidth(), img.getHeight());
    g2d.setFont(font);
    g2d.drawString(Text, 0, lm.getAscent());
    g2d.dispose();

    return img;
}

And final usage example:

public static void main(String[] args) {
    System.setProperty("apple.awt.UIElement", "true");
    showMenu(textToImage("Hello"), "Item - 1", "Item - 2");
}

System property apple.awt.UIElement=true is useful when you need to get rid of default java menu and cmd-tab icon, so your app behaves like it's background.

eleven
  • 6,779
  • 2
  • 32
  • 52