带有controlsfx通知组件的javafx NullPointerException [英] javafx NullPointerException with controlsfx Notifications componnets

查看:380
本文介绍了带有controlsfx通知组件的javafx NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开发一个使用controlsfx通知的应用程序,以便在系统托盘模式下显示一些通知。在正常模式下,我的应用程序运行良好,通知可以成功显示。但是当我在系统托盘中隐藏阶段时,会发生NullPointerException。我不知道如何解决这个问题。

I want to develop an application that uses controlsfx Notifications to show some notifications in system tray mode. In normal mode my application works well and notification can be shown successfully.but when I hide stage in system tray , NullPointerException occurs. I don't know how i can fix this problem.

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 javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;


public class TryIconNotification extends Application {
           private boolean firstTime;
private TrayIcon trayIcon;
@Override
public void start(Stage stage) throws Exception {
    firstTime = true;
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

     createTrayIcon(stage);
    firstTime = true;
    Platform.setImplicitExit(false);


    stage.setScene(scene);
    stage.show();
}


    public void createTrayIcon(final Stage stage) {
    if (SystemTray.isSupported()) {
        // get the SystemTray instance
        SystemTray tray = SystemTray.getSystemTray();
        // load an image
        java.awt.Image image = null;
        image = Toolkit.getDefaultToolkit().getImage("icons\\iconify.png");

        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent t) {
                hide(stage);
            }
        });

        // create a action listener to listen for default action executed on the tray icon
        final ActionListener closeListener = new ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                stage.hide();

            }
        };

        ActionListener showListener = new ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        stage.show();
                    }
                });
            }
        };
        // create a popup menu
        PopupMenu popup = new PopupMenu();

        MenuItem showItem = new MenuItem("Open app");

        showItem.addActionListener(showListener);
        popup.add(showItem);

        MenuItem closeItem = new MenuItem("Exit");
        closeItem.addActionListener(closeListener);
        popup.add(closeItem);
        /// ... add other items
        // construct a TrayIcon
        trayIcon = new TrayIcon(image, "Systray", popup);
        // set the TrayIcon properties
        trayIcon.addActionListener(showListener);
        // ...
        // add the tray image
        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            System.err.println(e);
        }
        // ...
    }
}
    public void showProgramIsMinimizedMsg() {
    //only in first time show the message
    if (firstTime) {
        trayIcon.displayMessage("System Tray",
                "Iconified",
                TrayIcon.MessageType.INFO);
        firstTime = false;
    }
}

        private void hide(final Stage stage) {
    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            if (SystemTray.isSupported()) {
                stage.hide();
                showProgramIsMinimizedMsg();
            } else {
                 System.exit(0);
                System.out.println("Not Support Sys Tray");
            }
        }
    });
}
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

这是我的控制器类:

import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.stage.Stage;
import org.controlsfx.control.Notifications;


public class FXMLDocumentController  implements Initializable   {

@FXML
private Label label;

@FXML
private void handleButtonAction(ActionEvent event) {
    Stage stage = (Stage) label.getScene().getWindow();
    stage.hide();
}

public void createNotification() {

    Notifications.create()
            .text("This is a Notification")
            .title("Notifications")
            .showInformation();
}

@Override
public void initialize(URL url, ResourceBundle rb) {

 Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {
          Platform.runLater(()->createNotification());
        }

    }, 5000, 10000);
}

}


推荐答案

我意识到当阶段进入隐藏模式并且通知需要在阶段显示时通知组件找不到阶段时会发生此异常。在互联网上搜索后,我找到了两个解决此问题的方法。

I realize that this exception occurs when the stage go to hide mode and the notification component cannot find stage when notification needs to show in stage. After searching in internet I find two solution for this problem.

解决方案1:

打开舞台并显示通知。
通过这种方式我们应该检查是否隐藏了舞台,打开它并显示通知。
要做到这一点,我们必须在CreateNotification方法中添加这个条件:

Open the stage and show notification. In this way we should check that if the stage was hidden, open it , and show notification. To do this we must add this condition in CreateNotification Method:

Stage stage = (Stage)  button.getScene().getWindow();
     if (!stage.isShowing()){
             stage.show();
     }

解决方案2:

在这个解决方案中,我们创建一个虚拟舞台并将其不透明度设置为零,然后隐藏主舞台。我在这个链接找到了这个解决方案,并将代码放在
这里

In this solution we create a dummy stage and set its opacity to zero and after that, hide the main stage. I find this solution at this link and put the code in here:

public void createDummyStage() {
    Stage dummyPopup = new Stage();
    dummyPopup.initModality(Modality.NONE);
    // set as utility so no iconification occurs
    dummyPopup.initStyle(StageStyle.UTILITY);
    // set opacity so the window cannot be seen
    dummyPopup.setOpacity(0d);
    // not necessary, but this will move the dummy stage off the screen
    final Screen screen = Screen.getPrimary();
    final Rectangle2D bounds = screen.getVisualBounds();
    dummyPopup.setX(bounds.getMaxX());
    dummyPopup.setY(bounds.getMaxY());
    // create/add a transparent scene
    final Group root = new Group();
    dummyPopup.setScene(new Scene(root, 1d, 1d, Color.TRANSPARENT));
    // show the dummy stage
    dummyPopup.show();
}

正如我提到的那样,我们应该在隐藏主阶段之前调用此方法:

As I mention bellow, We should call this method before hiding the main stage:

 @FXML
public void handleSysTryAction(ActionEvent event) {
    Stage stage = (Stage) button.getScene().getWindow();
    createDummyStage();
    stage.hide();
}

我实施这两个解决方案并且每件事都运作良好。如果你有一个更好的解决方案,请放在这里

I implement this two solution and every things works well. If you have a better solution for this problem please put here

你可以从我的 Dropbox

这篇关于带有controlsfx通知组件的javafx NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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