javafx 中是否可以有一个透明的实用程序阶段? [英] Is it possible to have a transparent utility stage in javafx?

查看:38
本文介绍了javafx 中是否可以有一个透明的实用程序阶段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道您可以将舞台设置为具有实用程序样式Stage.InitStyle(StageStyle.UTILITY);"您可以将其设置为具有透明样式Stage.InitStyle(StageStyle.TRANSPARENT);"但是你能同时拥有两者吗?我很累,让舞台不会在开始菜单中显示为向下的窗口,我希望舞台不可见,以便您只能看到场景.

I know that you can set a stage to have a utility style "Stage.InitStyle(StageStyle.UTILITY);" and you can set it to have a transparent style "Stage.InitStyle(StageStyle.TRANSPARENT);" but can you have both in the same stage? I am tiring to make it so that the stage does not show as a window down in the start menu and I would like the stage to be invisible so that you can only see the scene.

推荐答案

在该功能可用的情况下,您始终可以使用 Swing 以旧方式进行操作.Swing 允许您嵌入 JavaFX.当然,最好有一个没有 Swing 的干净机制,但它不存在(目前).

You can always do it the old way using Swing where that feature was available. And Swing allows you to embed JavaFX. Of course it would be preferred to have a clean mechanism without Swing, but afaik it doesn't exist (yet).

示例:

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.Background;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import java.awt.geom.GeneralPath;

public class Widget extends JFrame {

    class DragContext { 
        double x;
        double y; 
    } 

    public Widget() {

        // decoration
        setType(Type.UTILITY);
        setUndecorated(true);

        setSize(200, 200);

        toBack();

        // position
        // setLocation(100, 100);
        setLocationRelativeTo(null); // centers on screen

        // frame operations
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // frame shape (a star)
        double points[][] = { { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, { 40, 190 }, { 50, 125 }, { 0, 85 } };
        GeneralPath star = new GeneralPath();
        star.moveTo(points[0][0], points[0][1]);
        for (int k = 1; k < points.length; k++)
            star.lineTo(points[k][0], points[k][2]);
        star.closePath();

        setShape(star);

        // embed fx into swing
        JFXPanel fxPanel = new JFXPanel();

        Widget.this.getContentPane().add(fxPanel);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {

                // set scene in JFXPanel
                fxPanel.setScene( createFxScene());

                // show frame
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {

                        Widget.this.setVisible(true);

                        // send it to the desktop, behind all other existing windows
                        // Widget.this.toBack();
                        // Widget.this.repaint();
                    }
                });
            }
        });

    }

    private Scene createFxScene() {

        StackPane rootPane = new StackPane();
        rootPane.setBackground(Background.EMPTY);

        // add some node
        Label label = new Label("Bright & Shiny");
        label.setTextFill(Color.RED);

        rootPane.getChildren().add(label);

        // create scene
        Scene scene = new Scene(rootPane);

        // gradient fill
        RadialGradient radialGradient = new RadialGradient( 270, 0.8, 0.5, 0.5, 0.7, true, CycleMethod.NO_CYCLE, new Stop( .5f, Color.YELLOW), new Stop( .7f, Color.ORANGE), new Stop( .9f, Color.ORANGERED));
        scene.setFill(radialGradient);

        // context menu with close button
        ContextMenu contextMenu = new ContextMenu();

        MenuItem closeMenuItem = new MenuItem("Close");
        closeMenuItem.setOnAction(actionEvent -> System.exit(0));

        contextMenu.getItems().add(closeMenuItem);

        // set context menu for scene
        scene.setOnMousePressed(mouseEvent -> {
            if (mouseEvent.isSecondaryButtonDown()) {
                contextMenu.show(rootPane, mouseEvent.getScreenX(), mouseEvent.getScreenY());
            }
        });

        // allow the frame to be dragged around
        final DragContext dragDelta = new DragContext();

        rootPane.setOnMousePressed(mouseEvent -> {

            dragDelta.x = Widget.this.getLocation().getX() - mouseEvent.getScreenX();
            dragDelta.y = Widget.this.getLocation().getY() - mouseEvent.getScreenY();

        });

        rootPane.setOnMouseDragged(mouseEvent -> Widget.this.setLocation((int) (mouseEvent.getScreenX() + dragDelta.x), (int) (mouseEvent.getScreenY() + dragDelta.y)));

        return scene;
    }

    public static void main(String[] args) {
        new Widget();
    }

}

这是未显示在任务栏中的小部件的屏幕截图.用鼠标左键拖动它.鼠标右键提供了一个带有关闭按钮的上下文菜单.

Here's a screenshot of the widget that's not showing up in the task bar. Drag it with the left mouse button. Right mouse button offers a context menu with a close button.

上面的代码使用了摇摆框架的形状.下面的代码使用 javafx 控件的形状.

这是一个只有控件可见的版本.我使用反射标签控件.

Here's a version in which only the control is visible. I use a reflecting label control.

如果要将控件直接发送到桌面,则需要激活 toBack() 调用.您可以使用鼠标滚轮缩放控件.最大缩放大小受限于 jframe 的大小.

If you want to send the control directly to the desktop, you need to activate the toBack() invocation. You can zoom the control with the mouse wheel. The maximum zoom size is limited to the size of the jframe.

您需要为自定义控件做的就是在 createFxControl() 中实现代码

All you need to do for your custom control is implement the code in createFxControl()

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Control;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.effect.Reflection;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class LabelWidget extends JFrame {

    class DragContext { 
        double x;
        double y; 
    } 

    public LabelWidget() {

        // decoration
        setType(Type.UTILITY);
        setUndecorated(true);

        // make frame transparent, we only want the control to be visible
        setBackground(new java.awt.Color(0,0,0,0));

        setSize(400, 400);

        // position
        // setLocation(100, 100);
        setLocationRelativeTo(null); // centers on screen

        // frame operations
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // embed fx into swing
        JFXPanel fxPanel = new JFXPanel();

        LabelWidget.this.getContentPane().add(fxPanel);

        Platform.runLater(new Runnable() {
            @Override
            public void run() {

                // set scene in JFXPanel
                fxPanel.setScene( createFxScene());

                // show frame
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {

                        LabelWidget.this.setVisible(true);

                        // send it to the desktop, behind all other existing windows
                        // ClockWidget.this.toBack();
                        // ClockWidget.this.repaint();
                    }
                });
            }
        });

    }

    private Scene createFxScene() {

        StackPane rootPane = new StackPane();

        //  make pane transparent, we only want the control to be visible
        rootPane.setBackground(Background.EMPTY);

        // add control
        Control control = createFxControl();
        rootPane.getChildren().add( control);

        // create scene
        Scene scene = new Scene(rootPane);

        // make scene transparent, we only want the control to be visible
        scene.setFill( Color.TRANSPARENT);

        // context menu with close button
        ContextMenu contextMenu = new ContextMenu();

        MenuItem closeMenuItem = new MenuItem("Close");
        closeMenuItem.setOnAction(actionEvent -> System.exit(0));

        contextMenu.getItems().add(closeMenuItem);

        control.setContextMenu(contextMenu);

        // allow the frame to be dragged around
        makeDraggable( control);

        // allow zooming
        makeZoomable( control);

        return scene;
    }
    /**
     * Create the JavaFX control of which we use the shape.
     * @return
     */
    private Control createFxControl() {

        Label label = new Label( "I'm a Label");
        label.setFont(new Font("Tahoma", 24));
        label.setEffect(new Reflection());

        return label;
    }



    /**
     * Allow dragging of the stage / control on the desktop
     * @param control
     * @param stage
     */
    public void makeDraggable( Control control) {

        final DragContext dragDelta = new DragContext();

        control.setOnMousePressed(mouseEvent -> {

            dragDelta.x = LabelWidget.this.getLocation().getX() - mouseEvent.getScreenX();
            dragDelta.y = LabelWidget.this.getLocation().getY() - mouseEvent.getScreenY();

        });

        control.setOnMouseDragged(mouseEvent -> LabelWidget.this.setLocation((int) (mouseEvent.getScreenX() + dragDelta.x), (int) (mouseEvent.getScreenY() + dragDelta.y)));

    }

    /**
     * Allow zooming
     * @param control
     */
    public void makeZoomable( Control control) {

        // note: in order to make it larger, we'd have to resize the stage/frame => we limit the size to 1.0 for now and allow only making the control smaller
        final double MAX_SCALE = 1.0;
        final double MIN_SCALE = 0.1;
        control.addEventFilter(ScrollEvent.ANY, new EventHandler<ScrollEvent>() {
            @Override
            public void handle(ScrollEvent event) {
                double delta = 1.2;
                double scale = control.getScaleX();
                if (event.getDeltaY() < 0) {
                    scale /= delta;
                } else {
                    scale *= delta;
                }
                scale = clamp(scale, MIN_SCALE, MAX_SCALE);
                control.setScaleX(scale);
                control.setScaleY(scale);
                event.consume();
            }
        });

    }

    /**
     * Limit bounds of value
     * @param value
     * @param min
     * @param max
     * @return
     */
    public static double clamp( double value, double min, double max) {
        if( Double.compare(value, min) < 0)
            return min;
        if( Double.compare(value, max) > 0)
            return max;
        return value;
    }

    public static void main(String[] args) {
        new LabelWidget();
    }

}

或者如果你有来自 https://github.com/HanSolo/Enzo 手头,您可以使用此代码:

Or if you have the awesome Enzo library from https://github.com/HanSolo/Enzo at hand, you can use this code:

private Control createFxControl() {

    // create a clock using the enzo library from https://github.com/HanSolo/Enzo
    Clock clock = ClockBuilder.create()
            // .prefSize(400, 400)
            .design(Clock.Design.DB)
            .running(true)
            .text("Berlin")
            .autoNightMode(true)
            .build();


    return clock;
}

创建这个:

这篇关于javafx 中是否可以有一个透明的实用程序阶段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆