I have problem with JavaFX. I created two scenes and switch button.
When I click that button I'm changing scene. But earlier i set fullscreen on true and after I pressed the button, windows taskbar shows for a moment. Is there any way to change scenes without having this taskbar visible?
There is the code:
----Main class----
import java.io.IOException;
public class Main {
public static void main(String[] args) throws InterruptedException, IOException {
DesktopApplication.launch(DesktopApplication.class);
}
}
----DesktopApplication class----
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class DesktopApplication extends Application implements Runnable {
Scene firstScene;
Scene secondScene;
Scene scene;
public static Stage primaryStagePublic;
public DesktopApplication() {
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Title");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.initStyle(StageStyle.UNDECORATED);
int width = (int) Screen.getPrimary().getBounds().getWidth();
int height = (int) Screen.getPrimary().getBounds().getHeight();
HBox mainLayout = new HBox();
mainLayout.getChildren().add(new Text("hello!"));
MyLayout myLayout = new MyLayout(this);
firstScene = new Scene(myLayout,width,height);
secondScene = new Scene(mainLayout, width, height);
scene = firstScene;
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
primaryStage.show();
primaryStagePublic = primaryStage;
}
#Override
public void run() {
Thread thread = new Thread() {
public void run() {
launch(DesktopApplication.class);
}
};
thread.start();
while (true) {
}
}
public void swapScenes(Stage primaryStage){
primaryStage.setScene(secondScene);
primaryStage.setFullScreen(true);
primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
}
}
----MyLayout class----
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
public class MyLayout extends HBox{
private DesktopApplication desktopApplication;
public MyLayout(DesktopApplication desktopApplication) {
this.desktopApplication = desktopApplication;
init();
}
private void init(){
this.setStyle("-fx-background-color: #f8ff7d;");
Label text = new Label("testing");
Button button = new Button("Button");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
desktopApplication.swapScenes(DesktopApplication.primaryStagePublic);
}
});
this.getChildren().addAll(text, button);
}
}
I had a similar issue and solved it like #James_D suggested: Do not replace the scene as a whole, but only the root element:
public void swapScenes(Parent newContent){
stage.getScene().setRoot(newContent);
}
This requires changing the rest of the initialisation code a bit:
public class DesktopApplication extends Application implements Runnable {
Parent myLayout;
Parent mainLayout;
Scene scene;
public static Stage stage; // if possible make this private and non static
public DesktopApplication() {
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Title");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.initStyle(StageStyle.UNDECORATED);
int width = (int) Screen.getPrimary().getBounds().getWidth();
int height = (int) Screen.getPrimary().getBounds().getHeight();
mainLayout = new HBox();
mainLayout.getChildren().add(new Text("hello!"));
myLayout = new MyLayout(this);
scene = new Scene(myLayout,width,height);
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
primaryStage.show();
primaryStagePublic = primaryStage;
}
...
I personally solved it (After a few months of looking) by, instead of doing primaryStage.setFullScreen(true), which glitches or something, doing primaryStage.setMaximized(true) along with primaryStage.setWidth(var1) and primaryStage.setHeight(var2). My hypothesis on why setFullScreen deosn't work is a bug in full screen exclusive mode. Or, there just isn't enough permissions or something and it bugs out.
Related
Im working with javaFX and i would like to add a Rectangle object to the game root from a seperate player class. Therfor i created a getRoot function in my Game, and tried adding the rectangle from my player class. Although for some reason it just dosent work.
public class Test {
public void run() {
System.out.println("loaded");
GameScene gameScene = new GameScene();
gameScene.getRoot().getChildren().add(new Sprite(50,50,50,50, Color.GREEN,"TEST", 1, 0));
}
}
public class GameScene {
private Group root = new Group();
public Scene getScene(){
Scene scene = new Scene(root, Color.BLACK);
Test test = new Test();
test.run();
return scene;
}
public Group getRoot() {
return root;
}
}
The gameScene is still just empty when i run it, although the "loaded" string is printed to the console.
Try this for modifying root by another class:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class GameScene extends Application {
private Group root;
#Override
public void start(Stage stage) {
root = new Group();
stage.setScene(getScene());
stage.show();
}
public Scene getScene(){
Scene scene = new Scene(root);
Test test = new Test();
test.run(root);
return scene;
}
public static void main(String[] args) {
launch(args);
}
}
class Test {
public void run(Group root) {
root.getChildren().add(new Rectangle(50, 50, Color.BLACK));
}
}
I am creating a JavaFX desktop app on which I am simulating some work load. I want the app to have a progress indicator that updates dynamically (with time passing at the moment) to show how the load process is progressing. This is my application class:
public class App extends Application {
#Override
public void init() throws InterruptedException{
//Simulation of time consuming code.
for(int i = 0; i<=10; i++) {
notifyPreloader(new Preloader.ProgressNotification(i/10));
System.out.println("Progress is being set by the app to: " + (i/10));
Thread.sleep(500);
}
}
#Override
public void start(Stage primaryStage) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("/gui/fxml/App.fxml"));
Scene scene = new Scene(root, 600, 400);
scene.getStylesheets().add("/gui/style/app.css");
primaryStage.setScene(scene);
primaryStage.setTitle("Hello World!");
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This is my preloader class:
public class AppPreloader extends Preloader {
private Stage preloaderStage;
private Parent root;
private Scene scene;
private ProgressIndicator progress_indicator;
#Override
public void start(Stage primaryStage) throws Exception {
this.preloaderStage = primaryStage;
this.preloaderStage.setScene(this.scene);
this.preloaderStage.show();
this.progress_indicator = (ProgressIndicator) scene.lookup("#progressIndicator");
}
#Override
public void init() throws Exception {
root = FXMLLoader.load(getClass().getResource("/gui/fxml/AppPreloader.fxml"));
Platform.runLater(new Runnable() {
#Override
public void run() {
scene = new Scene(root, 600, 400);
scene.getStylesheets().add("/gui/style/appPreloader.css");
}
});
}
#Override
public void handleProgressNotification(ProgressNotification pn) {
if(pn instanceof ProgressNotification){
progress_indicator.setProgress(pn.getProgress());
System.out.println("Progress is being set by the handle method to: " + pn.getProgress());
}
}
#Override
public void handleStateChangeNotification(StateChangeNotification evt) {
if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
preloaderStage.hide();
}
}
}
Whit the print sentences I've been able to identify two problems: First, the
handleProgressNotification method is being called twice, once to be set to 0 and other to be set to 1, before the loop of the init method of the App class starts. Who is making the call? How can I avoid it?
The second problem is that the print sentence inside the init method of the app class is always printing 0.0. How can that be possible? Is it a matter of concurrency?
In addition I need to say that I've checked both of this questions (progressbar in preloader does not update and javafx preloader not updating progress) and didn't find a solution for my problem.
Thanks a lot for your time.
First, you're not seeing the progress values you expect because you are using integer arithmetic: i and 10 are both integers, so i/10 is 0 for 0 <= i < 10 and 1 when i=10.
Second, the handleProgressNotification and handleStateChangeNotification methods are part of the lifecycle of the application that are related to loading the resources. These are really leftovers from the days when JavaFX still supported web deployments and are probably of limited use now.
To receive notifications from the application, you need to override the handleApplicationNotification(...) method instead. Here is a corrected version of the two classes (also modified to be stand-alone so they can be copied and run: please provide these kinds of examples in your questions) that works:
package application;
import javafx.application.Application;
import javafx.application.Preloader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void init() throws InterruptedException{
//Simulation of time consuming code.
for(int i = 0; i<=10; i++) {
notifyPreloader(new Preloader.ProgressNotification(i/10.0));
System.out.println("Progress is being set by the app to: " + (i/10.0));
Thread.sleep(500);
}
notifyPreloader(new Preloader.StateChangeNotification(Preloader.StateChangeNotification.Type.BEFORE_START));
}
#Override
public void start(Stage primaryStage) {
Parent root;
root = new StackPane(new Label("Hello World"));
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Hello World!");
primaryStage.show();
}
}
package application;
import javafx.application.Preloader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class AppPreloader extends Preloader {
private Stage preloaderStage;
private Parent root;
private Scene scene;
private ProgressIndicator progress_indicator;
#Override
public void start(Stage primaryStage) throws Exception {
progress_indicator = new ProgressIndicator();
root = new StackPane(progress_indicator);
scene = new Scene(root, 600, 400);
this.preloaderStage = primaryStage;
this.preloaderStage.setScene(this.scene);
this.preloaderStage.show();
}
#Override
public void handleApplicationNotification(PreloaderNotification pn) {
if (pn instanceof ProgressNotification) {
//expect application to send us progress notifications
//with progress ranging from 0 to 1.0
double v = ((ProgressNotification) pn).getProgress();
progress_indicator.setProgress(v);
} else if (pn instanceof StateChangeNotification) {
StateChangeNotification scn = (StateChangeNotification) pn ;
if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
preloaderStage.hide();
}
}
}
}
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);
}
}
And this is my controller Class:
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.
Solution 1:
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();
}
Solution 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
You can download the complete Netbeans project from my Dropbox
I could not figure out why hamid's first solution was not working for me, until I debugged the Notifications creation. I found out, that beside the need of the Window to be isShowing it has to be isFocused too!
My solution is to call something like this method before Notifications.show():
private void focusStage() {
final Stage stage = (Stage) button.getScene().getWindow();
if (!stage.isShowing()) {
stage.show();
}
if (!stage.isFocused()) {
stage.requestFocus();
}
}
I can add a ChangeListener to a Scene and call it on the scene.widthProperty() and
scene.heightProperty(), but this doesn't apply when the window is maximized via the Maximize button.
I can't find any onResize property of the window when it is accessed like scene.getWindow()
Here's what I have to resize columns in a table based off resizing the window.
How can I make that resizeColumns listener be added to when the whole window is Maximized (which doesn't qualify as a scene.widthProperty() or scene.heightProperty()
ChangeListener<Object> resizeColumns = new ChangeListener<Object>(){
#Override
public void changed(ObservableValue arg0, Object arg1, Object arg2) {
new Thread() {
// runnable for that thread
public void run() {
Platform.runLater(new Runnable(){
public void run() {
// what will be ran in gui thread
Double width =primaryStage.getWidth();
DraftController controller = (DraftController)loader.getController();
TableView<Player> teamTable =controller.getTeamTable();
centerColumns(width, controller, teamTable);
TableView<Player> top10Table = controller.getTop10Table();
AnchorPane anchor = controller.getAnchorPane();
centerColumns(anchor.getWidth()+anchor.getWidth()*.04,controller,top10Table);
}
private void centerColumns(Double width, DraftController controller, TableView<Player> teamTable) {
ObservableList<TableColumn<Player, ?>> columnList = teamTable.getColumns();
for (int i=0 ; i<columnList.size(); i++){
columnList.get(i).setPrefWidth((width-17)/teamTable.getColumns().size());
}
}
});
}
}.start();
}
};
scene.widthProperty().addListener(resizeColumns);
scene.heightProperty().addListener(resizeColumns);
guage: lang-java -->
My little example works well on maximizing the stage:
package org.example;
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ResizeScene extends Application {
#Override
public void start(final Stage primaryStage) throws Exception {
final StackPane stack = new StackPane();
final Text resolution = new Text();
stack.getChildren().add(resolution);
final Scene scene = new Scene(stack);
primaryStage.setScene(scene);
final InvalidationListener resizeListener = new InvalidationListener() {
#Override
public void invalidated(final Observable observable) {
final double width = scene.getWidth();
final double height = scene.getHeight();
resolution.setText(width + " x " + height);
}
};
scene.widthProperty().addListener(resizeListener);
scene.heightProperty().addListener(resizeListener);
// Initial Size
primaryStage.setWidth(800);
primaryStage.setHeight(600);
primaryStage.show();
}
public static void main(final String[] args) {
launch(args);
}
}
Currently I have a TextField which is my address bar and a WebView which is my page. When I click ented the TextField doesn't seem to do anything. It's meant to run the loadPage method and set to page to load whatever the user entered into the address bar. Any help would be appreciated.
package javafx_webview;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Main extends Application {
WebEngine myWebEngine;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("Platinum v1");
TextField addressBar = new TextField();
addressBar.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
loadPage(event.toString());
}
});
WebView myBrowser = new WebView();
myWebEngine = myBrowser.getEngine();
StackPane root = new StackPane();
root.getChildren().add(myBrowser);
root.getChildren().add(addressBar);
primaryStage.setScene(new Scene(root, 640, 480));
primaryStage.show();
}
private void loadPage(String url) {
try {
myWebEngine.load(url);
} catch (Exception e) {
System.out.println("The URL you requested could not be found.");
}
}
}
Get the url to load from the text of the address bar, not the toString of the action event on the address bar.
final TextField addressBar = new TextField();
addressBar.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
myWebEngine.load(addressBar.getText());
}
});
Also the load is asynchronous, so your exception handler won't work. You need to monitor's the webengine loadworker's exception property to get exceptions from the engine. Also note that a url not found is not necessarily an exception which would be reported, instead a web server will usually return a page for a http 404 error.
Here is a working sample:
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.web.*;
import javafx.stage.Stage;
public class Main extends Application {
private WebEngine myWebEngine;
public void start(Stage stage) {
stage.setTitle("Platinum v1");
final TextField addressBar = new TextField();
addressBar.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
myWebEngine.load(addressBar.getText());
}
});
WebView myBrowser = new WebView();
myWebEngine = myBrowser.getEngine();
myWebEngine.getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
#Override public void changed(ObservableValue<? extends Throwable> observableValue, Throwable oldException, Throwable exception) {
System.out.println("WebView encountered an exception loading a page: " + exception);
}
});
VBox root = new VBox();
root.getChildren().setAll(
addressBar,
myBrowser
);
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) { launch(args); }
}