Créer une fenêtre non rectangulaire sans cadre sans barre de tâches dans JavaFX

Une note d'essais et d'erreurs lors de la tentative de création d'une application JavaFX qui n'apparaît pas dans la barre des tâches, comme des accessoires de bureau, et qui n'a pas de bordure et n'est pas carrée.

environnement

OS Windows 10

Java 1.8.0_162

Affichage de fenêtre sans barre des tâches

package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Main extends Application {
    
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.initStyle(StageStyle.UTILITY);
        Parent root = FXMLLoader.load(this.getClass().getResource("/main.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }
}

** Résultat d'exécution **

javafx.jpg

La description

--Si vous spécifiez StageStyle.UTILITY avec ʻinitStyle () of Stage`, vous pouvez créer une fenêtre qui ne s'affiche pas dans la barre des tâches.

Afficher une fenêtre non rectangulaire sans cadre

main.fxml

javafx.jpg

package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Main extends Application {
    
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.initStyle(StageStyle.TRANSPARENT);

        Parent root = FXMLLoader.load(this.getClass().getResource("/main.fxml"));
        Scene scene = new Scene(root);
        scene.setFill(Color.TRANSPARENT);
        primaryStage.setScene(scene);

        primaryStage.show();
    }
}

** Résultat d'exécution **

javafx.jpg

La description

Combinez les deux

UTILITY TRANSPARENT
Masquer la barre des tâches OK NG
Fenêtre non rectangulaire NG OK

Comme ça, chacun a les fonctions que vous voulez et les fonctions dont vous n'avez pas besoin, donc si vous vous tenez là, vous ne pouvez pas vous lever. En avril 2018, il ne semble y avoir aucun moyen de combiner ces deux proprement.

Le problème d'OpenJDK mentionne ce problème, mais il a été mis à jour pour la dernière fois en mai 2017 et il ne semble y avoir aucun progrès depuis.

[JDK-8091566] Taskbar-less Undecorated Transparent Window - Java Bug System

Combiner de force

Comme mentionné dans le problème ci-dessus, vous pouvez combiner les deux de force.

Plus précisément, c'est comme suit.

--Définissez la scène principale sur StageStyle.UTILITY et déplacez-la vers un endroit invisible en dehors de l'écran. ――Créez une autre étape et --Définissez StageStyle.TRANSPARENT --Définissez la scène principale au propriétaire

En d'autres termes, l'étape principale est utilisée uniquement pour utiliser la fonction de ʻUTILITYqui n'affiche pas la barre des tâches, et elle n'est pas affichée à l'écran, et la fenêtre visible réelle est faite par une autreétape avec TRANSPARENT`. La méthode.

javafx.jpg

Les préoccupations de cette méthode sont expliquées dans le problème ci-dessus comme suit:

This is a dangerous hack because that UTILITY window could get placed back on the main screen if the computer screen resizes like from a remote desktop session connect and the OS decides to place all windows back on the visible bounds. Tests have shown this doesn't happen, but it feels like it could in certain cases.

(Traduction) C'est un piratage dangereux. Cela est dû au fait que la fenêtre UTILITY peut revenir à la fenêtre principale si l'écran de l'ordinateur est redimensionné, par exemple en connectant une session de bureau à distance, et le système d'exploitation décide de renvoyer toutes les positions de la fenêtre dans la zone visible. Les tests disent que cela ne se produit pas, mais je pense que cela se produira probablement dans certains cas.

Il semble que cela ne se produit pas dans le test, mais il semble que ce ne soit pas une solution propre. Il est facile d'imaginer que si quelque chose ne va pas et que la scène principale est visible, ce sera assez moche.

Pour contourner le problème, j'ai également défini l''opacité 'de l'étape principale sur' 0 '. Si ʻopacity` est pris en charge, l'étage principal ne sera pas visible s'il entre accidentellement dans la zone visible. Cependant, cela n'a pas de sens dans un environnement où «opacity» n'est pas supporté, donc je pense qu'il sera nécessaire de le déplacer hors de l'écran.

Forme définitive

En plus de la combinaison forcée mentionnée ci-dessus, si l'implémentation telle que la barre d'état système est incluse, le résultat final sera le suivant.

main.fxml

javafx.jpg

Main.java


package sample.javafx;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import javax.imageio.ImageIO;
import java.awt.TrayIcon;
import java.awt.SystemTray;
import java.awt.AWTException;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class Main extends Application {

    private TrayIcon trayIcon;
    
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Platform.setImplicitExit(false);
        
        this.initPrimaryStage(primaryStage);
        Stage mainStage = this.initMainStage(primaryStage);
        this.initSystemTray(mainStage);
        
        primaryStage.show();
        mainStage.show();
    }
    
    private void initPrimaryStage(Stage primaryStage) {
        primaryStage.initStyle(StageStyle.UTILITY);
        primaryStage.setOpacity(0.0);
        primaryStage.setX(-1000);
        primaryStage.setY(-1000);
    }
    
    private Stage initMainStage(Stage primaryStage) throws IOException {
        Stage mainStage = new Stage();
        mainStage.initOwner(primaryStage);
        mainStage.initStyle(StageStyle.TRANSPARENT);
        
        FXMLLoader fxmlLoader = new FXMLLoader(this.getClass().getResource("/main.fxml"));
        Parent root = fxmlLoader.load();
        Scene scene = new Scene(root);
        scene.setFill(Color.TRANSPARENT);
        mainStage.setScene(scene);

        MainController controller = fxmlLoader.getController();
        controller.setStage(mainStage);

        return mainStage;
    }
    
    private void initSystemTray(Stage mainStage) throws IOException, AWTException {
        if (!SystemTray.isSupported()) {
            return;
        }
        
        BufferedImage img = ImageIO.read(this.getClass().getResource("/img/open.png "));
        this.trayIcon = new TrayIcon(img);
        this.trayIcon.setImageAutoSize(true);
        this.trayIcon.addActionListener(e -> {
            Platform.runLater(() -> {
                if (mainStage.isShowing()) {
                    mainStage.hide();
                } else {
                    mainStage.show();
                }
            });
        });
        this.trayIcon.setToolTip("show/hide");
        SystemTray systemTray = SystemTray.getSystemTray();
        systemTray.add(trayIcon);
    }

    @Override
    public void stop() {
        if (SystemTray.isSupported() && this.trayIcon != null) {
            SystemTray.getSystemTray().remove(this.trayIcon);
        }
    }
}

MainController.java


package sample.javafx;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public class MainController {
    private Stage stage;
    private double mouseOffsetX;
    private double mouseOffsetY;

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @FXML
    public void close() {
        Platform.exit();
    }

    @FXML
    public void onMousePressed(MouseEvent event) {
        this.mouseOffsetX = this.stage.getX() - event.getScreenX();
        this.mouseOffsetY = this.stage.getY() - event.getScreenY();
    }
    
    @FXML
    public void onMouseDragged(MouseEvent event) {
        this.stage.setX(event.getScreenX() + this.mouseOffsetX);
        this.stage.setY(event.getScreenY() + this.mouseOffsetY);
    }
}

** Résultat d'exécution **

On dirait que tu traînes

javafx.gif

On dirait qu'il est dans la barre d'état système

javafx.png

La description

Main.java


    @Override
    public void start(Stage primaryStage) throws Exception {
        Platform.setImplicitExit(false);

** Comment utiliser la barre d'état système avec JavaFX **

Recommended Posts

Créer une fenêtre non rectangulaire sans cadre sans barre de tâches dans JavaFX
Créer une base de données dans un environnement de production
Créer un programme Servlet dans Eclipse
Faisons une application de calculatrice avec Java ~ Créez une zone d'affichage dans la fenêtre
[Android] Créer un menu coulissant sans utiliser la vue de navigation
Créer un CSR avec des informations étendues en Java
Créez un cadre de traitement par lots simple dans Eclipse.
Essayez de créer un babillard en Java
Créer un onglet personnalisé avec SwiftUI 2.0
Créons un framework Web ultra-simple avec Java
Comment créer un thème dans Liferay 7 / DXP
Comment créer facilement un pull-down avec des rails
Commande Docker pour créer un projet Rails avec un seul coup dans l'environnement sans Ruby