setFullscreen in a ComboBox - javafx

Hello I am programming a UI for a game. In this UI I want a Scene with settings. In the settings I have a ComboBox where I want setFullscreen in true or false. Actually I get the Error "Cannot make a static reference to the non-static method setFullScreen(boolean) from the type " how can I solve my Problem. I want that the BorderlessWindow setFullscreen true the println are working.
CONTROLLER CLASS;
package Menue;
public class SettingEinstellungen {
#FXML
private ComboBox<String> Combobox;
ObservableList <String> Auswahl =
FXCollections.observableArrayList("Fullscree","Windowmode","Borderless Window");
#FXML
Button exit;
#FXML
public void initialize() {
Combobox.setValue("Fullscree");
Combobox.setItems(Auswahl);
Combobox.getSelectionModel().select("Fullscreen");
Combobox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>(){
public void changed(ObservableValue<? extends String> observable, String alt, String new) {
if(new != null) {
switch(new) {
case "Fullscreen": System.out.println("Vollbildgeklickt" +alt +neu);
break;
case "Window-mode": System.out.println("Fenster\t" +alt);
break;
case "Borderless Window": Stage.setFullScreen(true);
break;
default: ;
break;
}
}
}
});}
//public void changeCombo(ActionEvent event) {
//Stage.setFullscreen(true)(comboBox.getValue(Vollbild));
//}
#FXML
public void exit_press (ActionEvent event) throws IOException {
Stage window = (Stage)((Node)event.getSource()).getScene().getWindow();
//window.setFullScreen(true);
//window.setScene(new Scene(FXMLLoader.load(new File("menue_UI_1.fxml").toURI().toURL())));
Parent root_3 = FXMLLoader.load(getClass().getResource("menue_UI_2.fxml"));
Scene scene_3 = new Scene(root_3);
window.setScene(scene_3);
window.setTitle("Hauptmenü");
window.show();
}
}

The problem is that you are not referencing the actual stage which is why you are getting that error you need to reference the actual stage that is shown you can do this by getting the window during execution like so or you can initialize it at the top when you start the program
comboBox.getSelectionModel()
.selectedItemProperty()
.addListener((obs, oldVal, newVal) -> {
if(newVal != null) {
System.out.println(newVal);
switch(newVal) {
case "Fullscreen":
System.out.println("Vollbildgeklickt" +oldVal + newVal);
break;
case "Window-mode":
System.out.println("Fenster\t" +newVal);
break;
case "Borderless Window":
Stage window = (Stage) comboBox.getScene().getWindow();
window.setFullScreen(true);
break;
default:
break;
}
}
});

Related

Javafx setText for label is not working if scene is changed after

maybe someone will explain. I have a method, that sets label text if login is successful.
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + globalUser.getUserName()); //works
infoLine.setText("Redirecting to main dashboard..."); //works
}
}
And if I add additional code, which changes the scene after login, the label text is not changing:
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());//not working
infoLine.setText("Redirecting to main dashboard..."); //not working
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
How to solve this problem?
My controller class looks like this. Nothing special. After 2 validations it set texts of labels and changes scenes.
public class LoginController {
#FXML
private TextField username;
#FXML
private PasswordField password;
#FXML
private Label infoLine;
#FXML
private Label welcome;
#FXML
private Button exitBtn;
UserDao userDao = new UserDao();
#FXML
private void initialize() {
close();
}
#FXML
private void loginUser(ActionEvent event) throws IOException {
String user = username.getText();
String pass = password.getText();
if(validateFields(user, pass) && validateLogin(user, pass)) {
welcome.setText("Welcome, " + CurrentUser.getCurrentUser().getUserName());
infoLine.setText("Redirecting to main dashboard...");
//Changing scene after successful login
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
}
private boolean validateFields(String userName, String password) {
if (userName.isEmpty() || password.isEmpty()) {
infoLine.setText("Username and password can't be empty!");
return false;
}
return true;
}
private synchronized boolean validateLogin(String userName, String password) {
User user = userDao.getConnectedUser(userName, password);
if (user == null) {
infoLine.setText("User not found!");
return false;
}
CurrentUser.setCurrentUser(user);
return true;
}
private void close() {
exitBtn.setOnAction(SceneController::close);
}
}
Basically, the text is changing. The problem is as soon as the text is changed, you load the next view. This is happening really fast. The solution is to slow things down. Mainly, give the user time to see the text change before loading the new view. This can be done using PauseTransition.
After the text change, try the following code. After the text changes, this code gives a two-second delay before loading the new view.
PauseTransition pause = new PauseTransition(Duration.seconds(2));
pause.setOnFinished(
e -> {
Parent home = FXMLLoader.load(getClass().getResource(ScenePath.HOME.getPath()));
Scene homeScene = new Scene(home);
Stage appStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
appStage.setScene(homeScene);
appStage.show();
}
);
pause.play();

don't recieve mouse press event on child node JavaFX

I want draw path between two imageview same as picture
.
this path start from one of these imageview by mouse press, continue by mouse press and move event on pane and must be end in another imageview by mouse press.here is the problem after first mouse press didn't recieve any mouse press event on imageviews, the event just recieves on the pane becuase of that draw line didn't stop. what is wrong in my code ?
here's my controller code :
public class DrawLine {
#FXML
ImageView imageView1 ;
#FXML
ImageView imageView2 ;
#FXML
AnchorPane pane ;
private Line currentLine ;
private String state ;
private DoubleProperty mouseX = new SimpleDoubleProperty();
private DoubleProperty mouseY = new SimpleDoubleProperty();
#FXML
private void initialize(){
state = "dfkl" ;
imageView1.setPreserveRatio( false);
imageView2.setPreserveRatio( false);
imageView1.setOnMousePressed( event -> {
imageMousePress( event);
});
imageView2.setOnMousePressed( event -> {
imageMousePress( event);
});
pane.setOnMousePressed( event -> {
paneMousePress( event) ;
});
imageView2.setPickOnBounds(false);
imageView1.setPickOnBounds(false);
pane.setOnMouseMoved( event -> {
paneMouseMove( event);
});
}
public void paneMouseMove( MouseEvent e) {
if( this.state.equals("DRAWLINE") && this.currentLine != null) {
makeLine( e);
}
}
public void paneMousePress( MouseEvent e) {
if( this.state.equals("DRAWLINE") && this.currentLine != null) {
endLine(e);
startLine(e);
}
}
private void startLine( MouseEvent e ){
currentLine = new Line();
currentLine.setStyle( "-fx-stroke: #a86a6a ; -fx-stroke-width: 5");
currentLine.setStartX( e.getSceneX());
currentLine.setStartY(e.getSceneY());
mouseX.set( e.getSceneX()) ;
mouseY.set( e.getSceneY());
currentLine.endXProperty().bind(mouseX);
currentLine.endYProperty().bind(mouseY);
pane.getChildren().add(currentLine);
}
private void endLine ( MouseEvent e){
currentLine.endXProperty().unbind();
currentLine.endYProperty().unbind();
currentLine.setEndX(e.getX());
currentLine.setEndY(e.getY());
currentLine = null;
}
private void makeLine( MouseEvent e){
mouseX.set(e.getX());
mouseY.set(e.getY());
}
private void imageMousePress( MouseEvent event){
if( currentLine == null){
startLine(event);
state = "DRAWLINE" ;
}else if( currentLine != null & state.equals("DRAWLINE")){
endLine( event);
}
}
}
help me please.
When dragging the end point of the line around, the end is positioned below the mouse cursor. This way the target of the mouse event is the Line, not the ImageView and since there is no event handler for the event for the Line that consumes it, the event is delivered to the parent of the Line which is the AnchorPane, not the ImageView.
To fix this set the mouseTransparent property of the Line to true:
private void startLine(MouseEvent e) {
currentLine = new Line();
currentLine.setMouseTransparent(true);
...
}
Also you should consume the events for the ImageViews to not trigger the event handler for the AnchorPane too:
imageView1.setOnMousePressed(event -> {
imageMousePress(event);
event.consume();
});
imageView2.setOnMousePressed(event -> {
imageMousePress(event);
event.consume();
});
Also note that x and y properties of the MouseEvent are relative to the coordinate system of the Node where the handler is added.
private void endLine(MouseEvent e) {
currentLine.endXProperty().unbind();
currentLine.endYProperty().unbind();
currentLine.setEndX(e.getX());
currentLine.setEndY(e.getY());
currentLine = null;
}
needs to be changed to
private void endLine(MouseEvent e) {
currentLine.endXProperty().unbind();
currentLine.endYProperty().unbind();
currentLine = null;
}
Furthermore if there are a limited number of states, I recommend using a enum instead since this way you get compile time checks for typos. Using strings for this purpose you could accidentally add bugs, e.g. if you accidentally use "DRAWLlNE" instead of "DRAWLINE" which can be hard to spot. Additionally enum constants can be compared using ==.
private enum States {
DRAWLINE
}

How do i update a textfield in javafx in loop ?

I have a small javafx application using scene builder which on a button click should read a string from COM port at regular intervals and update in a text field.
But now it only shows the last string if I use a for loop, and nothing if i put the code in infinite loop (That's my temporary requirement).
Can anyone help me so that at each read from COM port the new string is updated in the text field.
Here is the code I used for both the cases :
Note : In both cases in controller class, I'm getting perfect output on console.
public class Main extends Application
{
#Override
public void start(Stage primaryStage)
{
try
{
Parent root = FXMLLoader.load(getClass().getResource("test.fxml"));
Scene scene = new Scene(root);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("test");
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
Here is the Controller class :
// In this case it shows only the last string in the text field.
public class Controller implements Initializable
{
#FXML
private Button sayHelloButton;
#FXML
private TextField helloField;
#Override
public void initialize(URL arg0, ResourceBundle arg1)
{
}
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
for(int i=0;i<5;i++)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
}
Here is the method with infinite loop :
//this shows nothing in the text field
#FXML
public void printHello(ActionEvent event)
{
if(event.getSource() == sayHelloButton)
{
SerialPort serialPort = new SerialPort("COM22");
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
helloField.clear();
helloField.setText(str);
}
catch(Exception e)
{
helloField.setText(e.toString());
}
}
}
}
There are a couple things happening here. In your first example, you state that the console output is correct but the TextField only shows the last result.
This is expected if the loop executes quickly. The TextField is being updated, but it happens so quickly that you can't see it until the loop ends and the last result is still being displayed. Even if you have a delay built into the loop, this could still block the UI from being updated until the loop is completed.
With your infinite loop, the issue is that the loop is being run on the JavaFX Application Thread (JFXAT). This blocks any updates to the GUI until the loop is finished, which is never is.
You will need to move the infinite loop to a new background thread. From there, you can update the GUI using the Platform.runLater() method.
SerialPort serialPort = new SerialPort("COM22");
new Thread(() -> {
while(true)
{
try
{
if(!serialPort.isOpened())
{
serialPort.openPort();
serialPort.setParams(9600, 8, 1, 0);
}
String str = serialPort.readString(10,3000);
System.out.println(str);
// Update the UI on the JavaFX Application Thread
Platform.runLater(() -> {
helloField.clear();
helloField.setText(str);
});
}
catch(Exception e)
{
Platform.runLater(() -> helloField.setText(e.toString()));
}
}
}).start();
This allows your UI to continually update as the background thread sends it new information.

Handle multiple JavaFX application launches within a loop

My code currently reads my Gmail inbox via IMAP (imaps) and javamail, and once it finds an email with zip/xap attachment, it displays a stage (window) asking whether to download the file, yes or no.
I want the stage to close once I make a selection, and then return to the place within the loop from which the call came. My problem arises because you cannot launch an application more than once, so I read here that I should write Platform.setImplicitExit(false); in the start method, and then use primartyStage.hide() (?) and then something like Platform.runLater(() -> primaryStage.show()); when I need to display the stage again later.
The problem occuring now is that the flow of command begins in Mail.java's doit() method which loops through my inbox, and launch(args) occurs within a for loop within the method. This means launch(args) then calls start to set the scene, and show the stage. Since there is a Controller.java and fxml associated, the Controller class has an event handler for the stage's buttons which "intercept" the flow once start has shown the stage. Therefore when I click Yes or No it hides the stage but then just hangs there. As if it can't return to the start method to continue the loop from where launch(args) occurred. How do I properly hide/show the stage whenever necessary, allowing the loop to continue whether yes or no was clicked.
Here is the code for Mail.java and Controller.java. Thanks a lot!
Mail.java
[Other variables set here]
public static int launchCount = 0;#FXML public Text subjectHolder;
public static ReceiveMailImap obj = new ReceiveMailImap();
public static void main(String[] args) throws IOException, MessagingException {
ReceiveMailImap.doit();
}
#Override
public void start(Stage primaryStage) throws Exception {
loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
root = loader.load();
controller = loader.getController();
controller.setPrimaryStage(primaryStage);
scene = new Scene(root, 450, 250);
controller.setPrimaryScene(scene);
scene.getStylesheets().add("styleMain.css");
Platform.setImplicitExit(false);
primaryStage.setTitle("Download this file?");
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void doit() throws MessagingException, IOException {
Folder inbox = null;
Store store = null;
try {
Properties props = System.getProperties();
Session session = Session.getDefaultInstance(props, null);
store = session.getStore("imaps");
store.connect("imap.gmail.com", "myAccount#gmail.com", "Password");
inbox = store.getFolder("Inbox");
inbox.open(Folder.READ_WRITE);
Message[] messages = inbox.getMessages();
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(UIDFolder.FetchProfileItem.FLAGS);
fp.add(UIDFolder.FetchProfileItem.CONTENT_INFO);
fp.add("X-mailer");
inbox.fetch(messages, fp);
int doc = 0;
int maxDocs = 400;
for (int i = messages.length - 1; i >= 0; i--) {
Message message = messages[i];
if (doc < maxDocs) {
doc++;
message.getSubject();
if (!hasAttachments(message)) {
continue;
}
String from = "Sender Unknown";
if (message.getReplyTo().length >= 1) {
from = message.getReplyTo()[0].toString();
} else if (message.getFrom().length >= 1) {
from = message.getFrom()[0].toString();
}
subject = message.getSubject();
if (from.contains("myAccount#gmail.com")) {
saveAttachment(message.getContent());
message.setFlag(Flags.Flag.SEEN, true);
}
}
}
} finally {
if (inbox != null) {
inbox.close(true);
}
if (store != null) {
store.close();
}
}
}
public static boolean hasAttachments(Message msg) throws MessagingException, IOException {
if (msg.isMimeType("multipart/mixed")) {
Multipart mp = (Multipart) msg.getContent();
if (mp.getCount() > 1) return true;
}
return false;
}
public static void saveAttachment(Object content)
throws IOException, MessagingException {
out = null; in = null;
try {
if (content instanceof Multipart) {
Multipart multi = ((Multipart) content);
parts = multi.getCount();
for (int j = 0; j < parts; ++j) {
part = (MimeBodyPart) multi.getBodyPart(j);
if (part.getContent() instanceof Multipart) {
// part-within-a-part, do some recursion...
saveAttachment(part.getContent());
} else {
int allow = 0;
if (part.isMimeType("application/x-silverlight-app")) {
extension = "xap";
allow = 1;
} else {
extension = "zip";
allow = 1;
}
if (allow == 1) {
if (launchCount == 0) {
launch(args);
launchCount++;
} else {
Platform.runLater(() -> primaryStage.show());
}
} else {
continue;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if ( in != null) { in .close();
}
if (out != null) {
out.flush();
out.close();
}
}
}
public static File createFolder(String subject) {
JFileChooser fr = new JFileChooser();
FileSystemView myDocs = fr.getFileSystemView();
String myDocuments = myDocs.getDefaultDirectory().toString();
dir = new File(myDocuments + "\\" + subject);
savePathNoExtension = dir.toString();
dir.mkdir();
System.out.println("Just created: " + dir);
return dir;
}
}
Controller.java
public class Controller implements Initializable {
#FXML
private Text subjectHolder;
public Button yesButton, noButton;
public ReceiveMailImap subject;
#Override
public void initialize(URL url, ResourceBundle rb) {
subject= new ReceiveMailImap();
subjectHolder.setText(subject.returnSubject());
}
public Stage primaryStage;
public Scene scene;
#FXML
ComboBox<String> fieldCombo;
public void setPrimaryStage(Stage stage) {
this.primaryStage = stage;
}
public void setPrimaryScene(Scene scene) {
this.scene = scene;
}
public String buttonPressed(ActionEvent e) throws IOException, MessagingException {
Object source = e.getSource();
if(source==yesButton){
System.out.println("How to tell Mail.java that user clicked Yes?");
return "POSITIVE";}
else{subject.dlOrNot("no");
System.out.println("How to tell Mail.java that user clicked No?");
primaryStage.hide();
return "NEGATIVE";}
}
}
There are a lot of issues with the code you have posted, but let me just try to address the ones you ask about.
The reason the code hangs is that Application.launch(...)
does not return until the application has exited
In general, you've kind of misunderstood the entire lifecycle of a JavaFX application here. You should think of the start(...) method as the equivalent of the main(...) method in a "traditional" Java application. The only thing to be aware of is that start(...) is executed on the FX Application Thread, so if you need to execute any blocking code, you need to put it in a background thread.
The start(...) method is passed a Stage instance for convenience, as the most common thing to do is to create a scene graph and display it in a stage. You are under no obligation to use this stage though, you can ignore it and just create your own stages as and when you need.
I think you can basically structure your code as follows (though, to be honest, I have quite a lot of trouble understanding what you're doing):
public class Mail extends Application {
#Override
public void start(Stage ignored) throws Exception {
Platform.setImplicitExit(false);
Message[] messages = /* retrieve messages */ ;
for (Message message : messages) {
if ( /* need to display window */) {
showMessage(message);
}
}
}
private void showMessage(Message message) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
Scene scene = new Scene(root, 450, 250);
stage.setScene(scene);
stage.initStyle(StageStyle.UNDECORATED);
stage.setTitle(...);
// showAndWait will block execution until the window is hidden, so
// you can query which button was pressed afterwards:
stage.showAndWait();
if (controller.wasYesPressed()) {
// ...
}
}
// for IDEs that don't support directly launching a JavaFX Application:
public static void main(String[] args) {
launch(args);
}
}
Obviously your logic for decided whether to show a window is more complex, but this will give you the basic structure.
To check which button was pressed, use showAndWait as above and then in your controller do
public class Controller {
#FXML
private Button yesButton ;
private boolean yesButtonPressed = false ;
public boolean wasYesPressed() {
return yesButtonPressed ;
}
// use different handlers for different buttons:
#FXML
private void yesButtonPressed() {
yesButtonPressed = true ;
closeWindow();
}
#FXML
private void noButtonPressed() {
yesButtonPressed = false ; // not really needed, but makes things clearer
closeWindow();
}
private void closeWindow() {
// can use any #FXML-injected node here:
yesButton.getScene().getWindow().hide();
}
}

Why is JavaFX WebEngine getLoadWorker looping?

I'm not very sure how to word this question but I'll try. My application runs commands against a website with a click of a button. The issue is during each loop the getLoadWorker increases by 1. In the load worker i set listeners. Here is how it works.
MenuItem executeToHere = new MenuItem("Execute to here");
executeToHere.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
listViewStepItem item = stepListView.getSelectionModel().getSelectedItem();
int selectedIndex = stepList.getSelectionModel().getSelectedIndex();
WebBrowser browser = new WebBrowser(item.getWebView(), item.getListView());
for(int i=0; i < selectedIndex; i++){
listViewStepItem item2 = stepList.getItems().get(i);
if(item2.comboBoxSelected.contains("http://")){
browser.loadURL();
} else if(item2.comboBoxSelected.contains("enter")){
browser.enterText();
} else if(item2.comboBoxSelected.contains("click")){
browser.click();
}
}
browser.setWorker();
}
});
public class WebBrowser{
public WebBrowser(WebView fxmlWebView, WebEngine webEngine){
this.view = fxmlWebView;
this.engine = webEngine;
}
public void loadUrl(String url){
webEngine.load(url);
}
public void enterText(){
System.out.println("ENTER TEXT");
}
public void click(){
System.out.println("click");
}
public void setWorker(){
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>(){
public void changed(ObservableValue ov, State oldState, State newState){
if(newState == javafx.concurrent.Worker.State.SUCCEEDED){
listener = new EventListener(){
public void handleEvent(org.w3c.dom.events.Event evt) {
eventListeners(evt);
}
};
setListenerByTagNames(listener, "a");
}
}
});
}
private void setListenerByTagNames(EventListener listener, String tagName){
Document doc = webEngine.getDocument();
NodeList elements = doc.getElementsByTagName(tagName);
for(int i=0; i < elements.getLength();i++){
((EventTarget) elements.item(i)).addEventListener("click", listener, false);
}
System.out.println("Listening on :"+tagName);
}
}
the first time i run it the output looks like this
ENTER TEXT
click
Listening on : a
second time
ENTER TEXT
click
Listening on : a
Listening on : a
third time
ENTER TEXT
click
Listening on : a
Listening on : a
Listening on : a
I don't see how the worker is increasing but it causes the page to reload/refresh somehow and therefore all the changes to the page DOM is reset.

Resources