2015-12-23 3 views
3

Я хочу разработать приложение, которое использует controlfx Notifications для отображения некоторых уведомлений в режиме системного трея. В нормальном режиме мое приложение работает хорошо, и уведомление может быть показано успешно. Но когда я скрываю сцену в системном трее, возникает NullPointerException. Я не знаю, как я могу исправить эту проблему.javafx NullPointerException with controlsfx Уведомления componentnets

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); 
} 

} 
+0

Поиском этого сайта «Что такое NullPointerException и как это исправить?» – csmckelvey

ответ

2

Я понимаю, что это исключение возникает, когда стадия перейти в режим скрытия и компонент уведомления не может найти этап, когда уведомление должно показать на сцене. После поиска в Интернете я нахожу два решения этой проблемы.

Решение 1:

Открыть этап и шоу-уведомление. Таким образом, мы должны убедиться, что если сцена была скрыта, откройте ее и покажите уведомление. Чтобы сделать это, мы должны добавить это условие в методе CreateNotification:

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

Решения 2:

В этом решении мы создадим фиктивную сцену и установите его непрозрачность до нуля, и после этого, скрыть главное сцена. Я считаю этим решение по этой ссылке и поместить код в 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(); 
} 

Как я упоминаю ниже, мы должны назвать этот метод до сокрытия основного этапа:

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

я реализую это два решения и все работает хорошо. Если у вас есть лучшее решение для этой проблемы, пожалуйста, поместить здесь

Вы можете загрузить полный проект Netbeans от моего Dropbox

+0

Используя второе решение, делаете ли вы что-нибудь, чтобы избавиться от фиктивных всплывающих окон? – Tommo

Смежные вопросы