How to close the current window in JavaFX? - java

I'm using JavaFX to build an application. In some windows there's a button whose purpose is to close the current one. Currently I'm using this kind of approach, but I think it's not clean as I would like it to be.
public class AboutController {
#FXML
private Button aboutClose;
public void initialize() {
aboutClose.setOnAction(event ->
((Stage) (aboutClose.getScene().getWindow())).close());
}
}
Is there a better way to implement this task? How to get the stage I'm working on from the Controller without having to take it from the button itself?

Related

Run some code when a popup closes in my swing app

In my app I display a popup using JPopupMenu. I want to run some code when this popup closes (either directly, programmatically or when escape key is pressed). For windows I can attach a WindowListener but JPopupMenu doesn't have any corresponding feature, and SwingUtilities.windowForComponent returns the root window of the app. How do I implement this?
How about adding a PopupMenuListener to it? Something like:
jpopMenu.addPopupMenuListener(new PopupMenuListener
{
public void popupMenuCanceled(PopupMenuEvent popupMenuEvent)
{
//here the code you want to be executed at close
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent){}
public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {}
}
This should be automatically executed when you cancel/close the popMenu. I didn't add code to the other two methods, but feel free to play with them if needed.

Can you build a Swing GUI for an MVC-style game if the Controller doesn't have a reference to the Model?

I couldn't find any similar answers on here, but apologies if this it too specific to my own problem.
I am building a simple game using in Java that has both a command line interface and a GUI (activated using a command line flag). The way that the game is written is that the game logic (Model) has a reference to the input (Controller) and the output (View), but neither the input or output have a reference to the model (this was a requirement). The flow of the game is therefore controlled by a loop in the application model similar to:
while (!gameFinished) {
InputType in = input.getUserInput(); //1
performAction(in);
}
Now that I am trying to build a Swing GUI for this (not something I have experience in), I am struggling to see how it could work with event listening. It would ideally work in the way that when a button is pressed (new game, save game, exit game etc.), an InputType would be sent to the Model (essentially doing the same that the commented line does) to be handled accordingly. But if it doesn't hold a reference to the Model, it can't 'send' the InputType. I suppose I am looking to build a GUI that works with the Model 'asking' for input, rather than 'listening' for it.
Is this possible? And if so, can anyone provide me with any useful resources for solving this? If not, an explanation or potential alternative solution suggestion would be appreciated.
I'm not gonna go into whether your flow is right or wrong.
Create an event queue in input. Listeners can then add events to the queue. Model can then ask the Input whether there are unhandled events in the queue and perform an action depending on the event that occurred. Let model hold a reference to the view interface call the appropriate view method in the performAction method.
Pseudo code:
class Controller{
Queue<UIEvent> events;
void setupUI(){
button.addEventListener( new EventListener(){
Model.this.events.add(new TappedButtonEvent());
});
}
UIEvent dequeueEvent(){
if(events.size() > 0){
return events.pop()
}
return null;
}
}
class Model{
public void loop(){
while (!gameFinished) {
UIEvent in = input.dequeueEvent();
if(in != null){
performAction(in);
}
}
}
}
Do not encapsulate how something is displayed in Model, let view handle it.
interface View{
void displayExitMessage()
}
class CommandLineView implements View{
void displayExitMessage(){
this.commandLine.append("Are you sure you want to exit(Y/N)?");
}
}
class CommandLineView implements View{
void displayExitMessage(){
this.window.showDialog("Are you sure you want to exit?", Button.YES, Button.NO);
}
}

LibGDX Java JUnit Testing

I am making an android game with the libGDX Java game library. I would like to test my code but not quite sure how to go about it. I have set up testing and run sample tests like.
public class UnitTestExample {
#Test
public void oneEqualsOne() {
assertEquals(1, 1);
}
}
Now how do I test a function like
public void addListenerToExitButton(){
buttonExit.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {Gdx.app.exit();
}
});
}
This function adds a LibGDX event to a button called buttonExit (In this case, the event is to exit the game.)
I use JMockIt for unit testing for my LibGdx projects and it works like a charm.
For your case, I assume the method you want to test is in a screen class, in other words, that is the class you are testing. Therefore you need to mock up all dependencies of this class and then instantiate it.Again I assume that button instance would be a private member of that class. So, under normal circumstances, you can not access it from your test code. JMockit can help you with that:
TextButton buttonToTest = (TextButton) Deencapsulation.getField(yourScreenUnderTest, "yourButtonName");
buttonToTest.toggle();
Above code will get the button and emulate click event on it. In this context, Gdx.app is a dependency and you already have mocked it up. What it means that, when your button is clicked, your mock instance will expect and exit call without any parameters. So, if you add this to your expectations, you are done.
Simple and elegant =]

Terminate JavaFX Application using Platform.exit()

I am using JavaFX 2.2 and I have a class which extends Application. Here is my code:
Class A extends Application {
public void Stage(final Stage primaryStage) { ... }
public void Start(){
launch();
}
btnLogin.setOnAction(new EventHandler<ActionEvent>() {
Platform.exit();
}
}
Class B{ }
Class C extends Application{
public void Stage(final Stage primaryStage) { ... }
public void Start(){
launch();
}
}
Actually, Class A is login screen; it will close when I successfully log in. Then the screen closed by platform.exit() function. After that I execute view button in Class B , Class C called but there are some problems.
java.lang.IllegalStateException: Application launch must not be called more than once
I just terminate the screen by using Platform.exit() function but I can't understand why it can't be closed.
Platform.exit() actually terminates whole jfx.
To keep things safe, just invoke launch() once and show/hide new windows.
Something like:
Platform.setImplicitExit(false);//make fx running in backgound.
Platform.runLater/AndWait {//make sure u create window in jfx thread
//window creation/show code here.
}
If Class B is the main screen and you need to Embed JavaFX in your application for Login Screen or any other screen, you don't need Class A and Class C to extend Application.
You can just create a new Window in Swing inside these classes (A and C) and use JFXPanel to embed JavaFX into your Swing Application. This way you can have full control on the application and you can easily open and close windows for Login or any other functionality that you want.
N.B. You should not have two class extending Application inside one app, as only one JavaFX thread is allowed per JVM.
Everytime you try to do this you will get this error
java.lang.IllegalStateException: Application launch must not be called more than once

Thin controllers

I am getting my feet wet with javafx. This is what I am doing.
FXML Views
DI Controllers
Weld-SE Managed Services and Models
Trying to confine UI to FXML
Trying keep the Controllers thin
Problem:
While trying to code the UI, most static UI is confined inside the fxml. But there are scenarios where I find my self adding, removing, showing, hiding elements etc.
I find myself doing this inside the controller as fx lets me configure controller method in the view which it will call on a particular action / event. All this code deals with Dynamic UI building / manipulating and belongs inside the view layer. But, it ends up in controller making the controllers fat.
javafx provides javascript integration. This is one possible way to abstract that view manupulation code away. But this would add not so perfect javascript into the mix.
How would I abstract the code away in java or fxml so that I don't break the Thin Controller Paradigm ?
EDIT
#assylias
Agreed, I have thought about this and this way that java class and fxml together become a reusable widget. But then, how do I wire this into FXML. FXML doesn't understand anything but a controller. Let say I wire this view class into fxml using fx:controller and not name it controller. So I have something like this.
This view class has nothing but view manipulation code. Then I would create another controller class. But then I would expect to somehow fill the form data into this controller. This should only happen when the user has submitted the form. So in a way, I need to tell javafx somehow that UI manipulation request / event is different from actual data manipulation request / event.
Your thoughts, sorry if it was verbose. Tried to articulate it in as few words as I could.
I think the easiest solution to this is to remember that the controller specified in FXML is a view controller. It's purpose is to contain code to modify and update the view, not to contain traditional MVC controller code or business logic.
For example, in a project I'm currently working on, I'm using JavaFX with Akka Actors. The application is written in scala. The JavaFX view controllers contain any code necessary to modify the view. One screen contains a login form. When the user clicks the login button, the view controller simply creates a message containing the username and password, and sends that message to the actor responsible for doing business logic. If that actor determines there is an error then it will send a message back to the view controller, and the view controller can decide what sort of updates need to be made on the screen.
I've found that using akka actors with JavaFX greatly simplifies coding the application for at least two reasons.
Because using an actor system mandates sending messages between actors, there is a natural boundary between presentation code and business code. The messages that are passed back and forth form this natural boundary.
Using actors completely replaces the complexity of working with threads/tasks. It completely eliminates the need to code javafx.concurrent.Task's for long running processes.
How about putting your view manipulation code in Main Class ?
Main Class :
public class SampleJavaFXApp extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"SampleUI.fxml"));
Parent root = (Parent) loader.load();
Controller controller = loader.getController();
viewManipulationLogic(controller);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
// view manipulation logic
private void viewManipulationLogic(Controller controller) {
controller.getBlueButton().setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println(" I am just about button!");
}
});
}
Controller :
public class Controller implements Initializable {
#FXML
private Button blueButton;
public Button getBlueButton() {
return blueButton;
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
//real data manipulation
}
}
cons : You need getters for all Nodes u want to manipulate , in controller class.

Categories

Resources