I have this simple controller:
#FXML
private VBox VVbox;
private ButtonBar newNode = new ButtonBar();
private Circle c= new Circle();
private Button b= new Button();
private Label lname = new Label();
private Label lIMEI = new Label();
private Label lroot = new Label();
#Override
public void initialize(URL location, ResourceBundle resources) {
// TODO Auto-generated method stub
}
public void create(String imei){
System.out.println(imei);
newNode = new ButtonBar();
b = setButtonSpec(imei + "btnHavefun");
c = setCircleSpec(imei + "statuOnline");
lname= setLNameSpec(imei + "name");
lIMEI = setLIMEISpec(imei + "Imei");
lroot = setLrootSpec(imei + "root");
newNode.getButtons().addAll(lname,lIMEI,lroot,b,c);
VVbox.getChildren().addAll(newNode) ;
}
this is my main:
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Thypheon Application");
Connection connessione = new Connection();
Thread t = new Thread(connessione);
initDesign();
t.start();
}
public static void main(String[] args) {
launch(args);
}
public void initDesign(){
try {
loader2= new FXMLLoader(getClass().getResource("Design.fxml"));
AnchorPane anchor = (AnchorPane) loader2.load();
rootLayout.setCenter(anchor);
controller = loader2.getController();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
As you can see in main I start a new thread in which I would like a Controller function.
public class Connection implements Runnable {
String result;
Controller controller = new Controller();
public void run() {
controller.create("TEST123");
}
Everything seems to be inside create function until The last line is executed: VVbox.getChildren().addAll(newNode) ;
Probably because it has a reference to the FXML file.. How can I solve this?
Yes you are right. The controller that you instantiate yourself does not get its fields injected by FXML. To obtain a reference to the controller the following is a possible solution:
public Controller initDesign(){
// some FXML loading code
return controller;
}
You will then need to modify your Connection to take a Controller object in the constructor:
class Connection ... {
Controller contoller;
public Connection(Controller controller) {
this.controller = controller;
}
}
Finally in start() you will need:
Controller controller = initDesign();
Connection connessione = new Connection(controller);
Thread t = new Thread(connessione);
t.start();
However, there is more than one issue with your design.
Your Connection instance is NOT run on JavaFX Application Thread. Therefore, any attempt to modify the scene graph from a different thread (e.g. your call to VVbox.getChildren().addAll(newNode);) will cause an error.
The start() method is called from JavaFX Thread. There is no need to create a new thread. I am unsure of the intentions, but you can call your create() from Controller in start() to be executed on JavaFX Thread.
Related
Update:
WorldConfiguration and World are still the same,
WorldConfiguration setup = new WorldConfigurationBuilder()
.with(new HelloSystemArtemis())
.with(new RenderSystem(batch, environment))
.with(new BulletSystem(this))
.with(new PlayerSystem(perspectiveCamera, batch, gameUi, this))
.with(new AthmosphereSystem(modelComponent,
bulletComponent))
.with(new MovementSystem(this))
.with(new StatusSystem(this))
.with(new EnemySystem(this))
.build();
World world = new World(setup);
world.setDelta(delta);
int entityId = world.create();
world.edit(entityId).create(HelloComponentArtemis.class).message = "\n\rHello Oxyddians!\n\r";
Decided to post full code for clarity reason, in fact can't explain from where the problem is coming, even if I got errors that point me to
#All({ModelComponentArtemis.class, ModelComponentArtemis.class})
public class AthmosphereSystem extends BaseSystem {
private static OxyddiA game;
private static Assets assets = new Assets();
private ComponentMapper<ModelComponentArtemis> mc;
private ComponentMapper<BulletComponentArtemis> bc;
public AthmosphereSystem(ComponentMapper<ModelComponentArtemis> mc,
ComponentMapper<BulletComponentArtemis> bc) {
this.mc = mc;
this.bc = bc;
}
#Override
protected void processSystem() {
int entity = world.create();
ModelComponentArtemis mc = new ModelComponentArtemis(assets.Athmosphere,0,0,0);
mc.create(entity); //Not working
BulletComponentArtemis bc = new BulletComponentArtemis();
btCollisionShape shape = Bullet.obtainStaticNodeShape(assets.Athmosphere.nodes);
bc.bodyInfo = new btRigidBody.btRigidBodyConstructionInfo(0, null, shape, Vector3.Zero);
bc.body = new btRigidBody(bc.bodyInfo);
bc.body.userData = entity;
bc.motionState = new MotionState(mc.instance.transform);
((btRigidBody) bc.body).setMotionState(bc.motionState);
bc.create(entity); //Not working
return entity; //Not working as well
}
}
ModelComponent used in this approach
public class ModelComponentArtemis extends Component {
public Model model;
public ModelInstance instance;
public ModelComponentArtemis(Model model, float x, float y, float z)
{
this.model = model;
this.instance = new ModelInstance(model, new Matrix4().setToTranslation(x, y, z));
}
public void reset() {
}
}
BulletComponent used in this approach
public class BulletComponentArtemis extends Component {
public MotionState motionState;
public btRigidBody.btRigidBodyConstructionInfo bodyInfo;
public btCollisionObject body;
public Model model;
public void init() {
ModelComponentArtemis modelComponent = new ModelComponentArtemis(model,0,0,0);
BulletComponentArtemis bulletComponent = new BulletComponentArtemis();
btCollisionShape shape = Bullet.obtainStaticNodeShape(model.nodes);
bulletComponent.bodyInfo = new btRigidBody.btRigidBodyConstructionInfo(0, null, shape, Vector3.Zero);
bulletComponent.body = new btRigidBody(bulletComponent.bodyInfo);
Object bCuD = null;
bulletComponent.body.userData = bCuD;
bulletComponent.motionState = new MotionState(modelComponent.instance.transform);
((btRigidBody) bulletComponent.body).setMotionState(bulletComponent.motionState);
}
public void reset() {
}
}
And of course the BulletSystem used in this project
#All(ModelComponentArtemis.class)
public class BulletSystem extends EntitySystem
{
public Entity e;
public final btCollisionConfiguration collisionConfiguration;
public final btCollisionDispatcher dispatcher;
public final btBroadphaseInterface broadphase;
public final btConstraintSolver solver;
public final btDiscreteDynamicsWorld collisionWorld;
public GameWorld gameWorld;
public PreGameWorld preGameWorld;
private final btGhostPairCallback ghostPairCallback;
public final int maxSubSteps = 5;
public final float fixedTimeStep = 0.2f / 60f;
private EntityContactListener myContactListener;
public BulletSystem(GameWorld gameWorld)
{
super(Aspect.all(ModelComponentArtemis.class));
this.gameWorld = gameWorld;
myContactListener = new EntityContactListener();
myContactListener.enable();
collisionConfiguration = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfiguration);
broadphase = new btAxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
solver = new btSequentialImpulseConstraintSolver();
collisionWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
ghostPairCallback = new btGhostPairCallback();
broadphase.getOverlappingPairCache().setInternalGhostPairCallback(ghostPairCallback);
this.collisionWorld.setGravity(new Vector3(0f, -0.5f, 0f));
}
public BulletSystem(PreGameWorld preGameWorld)
{
this.preGameWorld = preGameWorld;
myContactListener = new EntityContactListener();
myContactListener.enable();
collisionConfiguration = new btDefaultCollisionConfiguration();
dispatcher = new btCollisionDispatcher(collisionConfiguration);
broadphase = new btAxisSweep3(new Vector3(-1000, -1000, -1000), new Vector3(1000, 1000, 1000));
solver = new btSequentialImpulseConstraintSolver();
collisionWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
ghostPairCallback = new btGhostPairCallback();
broadphase.getOverlappingPairCache().setInternalGhostPairCallback(ghostPairCallback);
this.collisionWorld.setGravity(new Vector3(0f, -0.5f, 0f));
}
public void update(float deltaTime)
{
collisionWorld.stepSimulation(deltaTime, maxSubSteps, fixedTimeStep);
}
protected void processSystem(int entityId) {
this.world.getEntity(entityId).getComponent(BulletComponentArtemis.class);
}
#Override
protected void processSystem() {
}
public void dispose()
{
collisionWorld.dispose();
if (solver != null) solver.dispose();
if (broadphase != null) broadphase.dispose();
if (dispatcher != null) dispatcher.dispose();
if (collisionConfiguration != null)
collisionConfiguration.dispose();
ghostPairCallback.dispose();
}
}
With all that in mind, I know I just can't find any solution,
Maybe it will be clearer like that for anyone wishing to help
Thanks anyawy.
Couple of things to note:
you don't need to inject entity instances
working with Entity and EntityEdit is slower than working with int and ComponentMapper/Archetype/EntityTransmuter, but fine for the beginning.
What you probably want to do is creating an AtmosphereSystem (extending BaseSystem) and create the entity within the initialize method or offer a public method (non-static).
If you need to call those entity factory methods, just inject the AtmosphereSystem (or anything extending BaseSystem) by adding a field "AtmosphereSystem atmosphereSytem;" inside any other BaseSystem.
See this gist for a similar use case (factory methods for creating entities).
I'm working with JavaFX and my Idea was to have my own JavaFX Object which I can create like this:
public class Main {
public static void main(String[] args) throws Exception
TSS t = new TSS();
}
}
My JavaFX Main class looks like this:
public class TSS extends Application {
private Scene scene;
private Stage stage;
public void redrawGui() throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("tss.fxml"));
scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
this.stage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("tss.fxml"));
scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Normally the main method in TSS is called and its working but I want to create my own TSS-Object in its constructor, it creates the Gui.
Does anyone know how to do this?
In JavaFX, you should (typically) think of the Application subclass as the "main" class (i.e. the application entry point) and its start(...) method as the replacement for the main(...) method in a "traditional" Java Application.
If you want to factor your code out into a class that is separate from the Application subclass (which is generally a good idea), then you can do so, but you need to just reorganize things a little:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TSS t = new TSS();
Scene scene = new Scene(t.getView());
primaryStage.setScene(scene);
primaryStage.show();
}
// not really needed in Java 8, but some IDEs need this to execute this class:
public static void main(String[] args) { launch(args);}
}
And then you can define your own class as follows:
public class TSS {
private Parent view ;
private TssController controller ; // controller class specified in FXML
public TSS() throws Exception {
load();
}
private void load() throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("tss.fxml"));
view = loader.load();
controller = loader.getController();
}
public Parent getView() {
return view ;
}
public void restartGui() throws Exception {
Scene scene = view.getScene();
Stage stage = null ;
if (scene != null) {
Window window = scene.getWindow();
if (window instanceof Stage) {
stage = (Stage) window ;
}
}
load();
if (stage != null) {
stage.setScene(new Scene(view));
}
}
public void doOtherStuff() {
controller.doSomething();
}
}
You could also consider implementing the TSS class above using the custom control pattern described in the FXML documentation. I marginally prefer the style I showed here, as it favors composition over inheritance, but it is a minimal difference.
So, I'm developing a program using the Swing library and I obviously have buttons and menu items. Some of these are supposed to do the same stuff, and I thought using the Command Pattern should be the way to do it, e.g. I have a "save" button and a "save" menu item and they have to implement the same saving algorithm.
Command Pattern seems to be ok but I can't get who's the receiver in all that. Isn't a comand supposed to work on an object which implements some sort of "receiver interface", so that you can use different commands on different receivers coupling them aribtrarily? It looks like there's no "receiver" in my implementation of the pattern.
Another doubt i have is should a command be implemented as a singleton, since you could potentially call its functions from differents parts of the same project, and it would be handly to instantiate it only once and make it statically invokable?
Thank you.
" I obviously have buttons and menu items. Some of these are supposed to do the same stuff,"
As #nIcEcOw noted, that's what Actions are for. This Answer Shows exactly this.
As stated in the How to use Actions :
An Action can be used to separate functionality and state from a component. For example, if you have two or more components that perform the same function, consider using an Action object to implement the function. An Action object is an action listener that provides not only action-event handling, but also centralized handling of the state of action-event-firing components such as tool bar buttons, menu items, common buttons, and text fields. The state that an action can handle includes text, icon, mnemonic, enabled, and selected status.
An There only three Actions. Ont to open, save, and new. Each Action has an ActionCommand, and icon, and and action to perform. Both the JMenuItem and JToolBar button share the same Action and do the same thing. Here is the code you can run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
public class ActionTest {
public ActionTest() {
ImageIcon openIcon = new ImageIcon(
ActionTest.class.getResource("/resources/image/open.gif"));
ImageIcon saveIcon = new ImageIcon(
ActionTest.class.getResource("/resources/image/save.gif"));
ImageIcon newIcon = new ImageIcon(
ActionTest.class.getResource("/resources/image/new.gif"));
Action openAction = new AbstractAction("Open", openIcon) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Open File");
}
};
Action saveAction = new AbstractAction("Save", saveIcon) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Save File");
}
};
Action newAction = new AbstractAction("New", newIcon) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("New File");
}
};
JMenuItem openMenuItem = new JMenuItem(openAction);
JMenuItem saveMenuItem = new JMenuItem(saveAction);
JMenuItem newMenuItem = new JMenuItem(newAction);
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
fileMenu.add(openMenuItem);
fileMenu.add(saveMenuItem);
fileMenu.add(newMenuItem);
menuBar.add(fileMenu);
JToolBar toolBar = new JToolBar();
toolBar.add(Box.createHorizontalGlue());
toolBar.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
toolBar.add(newAction);
toolBar.add(openAction);
toolBar.add(saveAction);
JFrame frame = new JFrame("Toolbar and Menu Test");
frame.setJMenuBar(menuBar);
frame.add(toolBar, BorderLayout.PAGE_START);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ActionTest();
}
});
}
}
As stated in the quote from the above mentioned tutorial, you can do more than just add an image and an action command to the Action. You can use it to set mnemonics and accelorators. Here is a custom Action class that takes
An action command String
an icon
a description for tooltips
a mnemonic
and a key accelorator.
private class MyAction extends AbstractAction {
String name;
public MyAction(String name, Icon icon) {
super(name, icon);
this.name = name;
}
public MyAction(String name, Icon icon, String desc,
Integer mnemonic, KeyStroke accelorator) {
super(name, icon);
putValue(Action.SHORT_DESCRIPTION, desc);
putValue(Action.MNEMONIC_KEY, mnemonic);
putValue(Action.ACCELERATOR_KEY, accelorator);
this.name = name;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (name) {
case "Open":
System.out.println("Open");
break;
case "New":
System.out.println("New");
break;
case "Save":
System.out.println("Save");
break;
}
}
}
Here's an instantiation of this Action
Action newAction = new MyAction("New", newIcon,
"Creates a new file",
new Integer(KeyEvent.VK_N),
KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
And here's the new result. You will see the actionCommand in the menu, along with the key mnemonics and accelerators, tooltips, and you will see the jtoolbar buttons share the same traits. You will also see in the final code, that never once once a component created. All you do is add the Action to the JToolBar and the JMenu and let them work their magic.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ActionInterfaceDemo extends JFrame {
public ActionInterfaceDemo() {
ImageIcon openIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/open.gif"));
ImageIcon saveIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/save.gif"));
ImageIcon newIcon = new ImageIcon(ActionInterfaceDemo.class.getResource("/resources/image/new.gif"));
Action openAction = new MyAction("Open", openIcon,
"Opens a file",
new Integer(KeyEvent.VK_O),
KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
Action saveAction = new MyAction("Save", saveIcon,
"Saves a file",
new Integer(KeyEvent.VK_S),
KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
Action newAction = new MyAction("New", newIcon,
"Creates a new file",
new Integer(KeyEvent.VK_N),
KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
setJMenuBar(menuBar);
menuBar.add(fileMenu);
fileMenu.add(newAction);
fileMenu.add(openAction);
fileMenu.add(saveAction);
JToolBar toolBar = new JToolBar("Alignment");
toolBar.setBorder(BorderFactory.createLineBorder(Color.BLUE));
toolBar.add(Box.createHorizontalGlue());
toolBar.add(newAction);
toolBar.add(openAction);
toolBar.add(saveAction);
add(toolBar, BorderLayout.PAGE_START);
add(new JScrollPane(new TextArea(10, 40)), BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Action Interface Demo");
pack();
setLocationByPlatform(true);
setVisible(true);
}
private class MyAction extends AbstractAction {
String name;
public MyAction(String name, Icon icon) {
super(name, icon);
this.name = name;
}
public MyAction(String name, Icon icon, String desc,
Integer mnemonic, KeyStroke accelorator) {
super(name, icon);
putValue(Action.SHORT_DESCRIPTION, desc);
putValue(Action.MNEMONIC_KEY, mnemonic);
putValue(Action.ACCELERATOR_KEY, accelorator);
this.name = name;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (name) {
case "Open":
System.out.println("Open");
break;
case "New":
System.out.println("New");
break;
case "Save":
System.out.println("Save");
break;
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ActionInterfaceDemo();
}
});
}
}
UPDATE
The better explain the relationship of Action and Command Patterns
As noted in Command Pattern
The command pattern is a commonly used pattern which encapsulates a method call or action-like code into a single class. The advantages of being able to package a method (or methods) into a class become evident when you have multiple invokers for a single action (for example a button and a menu item may perform the same action).
In Swing and Borland Delphi programming, an Action is a command object. In addition to the ability to perform the desired command, an Action may have an associated icon, keyboard shortcut, tooltip text, and so on. A toolbar button or menu item component may be completely initialized using only the Action object.
So basically Swing uses the concept of the command pattern through the use of Actions
As for OP's question
"Command Pattern seems to be ok but I can't get who's the receiver in all that."
As for the receiver, the wiki uses a text editor as an example and defines the receiver as such
Receiver, Target Object: the object that is about to be copied, pasted, moved, etc. The receiver object owns the method that is called by the command's execute method. The receiver is typically also the target object. For example, if the receiver object is a cursor and the method is called moveUp, then one would expect that the cursor is the target of the moveUp action. On the other hand, if the code is defined by the command object itself, the target object will be a different object entirely.
The main more components of a Command Pattern are stated as follows
Four terms always associated with the command pattern are command, receiver, invoker and client.
Client, Source, Invoker: the button, toolbar button, or menu item clicked, the shortcut key pressed by the user.
So to put it all together:
The MenuItem (client) invokes it
Action (command object) which calls it actionPerformed which in turn
Invokes an method on the receiver.
The wiki article is good read with a Java example
When two or more components are mean to do exactly the same thingy, one should look at Action, which reduces the duplicate code.
Small example for further help :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionExample {
private JFrame frame;
private JButton button;
private JMenuItem exitItem;
private Action commonActions;
private class CommonActions extends AbstractAction {
public CommonActions(String title, String desc) {
super(title);
putValue(SHORT_DESCRIPTION, desc);
}
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame,
"Closing Frame", "Information", JOptionPane.INFORMATION_MESSAGE);
frame.dispose();
}
};
private void displayGUI() {
frame = new JFrame("Action Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
commonActions = new CommonActions("Exit", "To Exit the Application");
JPanel contentPane = new JPanel();
button = new JButton();
button.setAction(commonActions);
contentPane.add(button);
frame.setJMenuBar(getMenuBar());
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JMenuBar getMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
exitItem = new JMenuItem(commonActions);
fileMenu.add(exitItem);
menuBar.add(fileMenu);
return menuBar;
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ActionExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
ADDED an example with SINGLETON PATTERN (though I am not sure of this approach(about how good this approach is))
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionExample {
private JFrame frame;
private JButton button;
private JMenuItem exitItem;
private void displayGUI() {
frame = new JFrame("Action Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
CommonActions.setValues(frame);
JPanel contentPane = new JPanel();
button = new JButton();
button.setAction(CommonActions.getInstance());
contentPane.add(button);
frame.setJMenuBar(getMenuBar());
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JMenuBar getMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
exitItem = new JMenuItem(CommonActions.getInstance());
fileMenu.add(exitItem);
menuBar.add(fileMenu);
return menuBar;
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ActionExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class CommonActions extends AbstractAction {
private static CommonActions commonActions = null;
private static JFrame frame = null;
static {
try {
commonActions = new CommonActions("Exit", "To Exit the Application");
} catch (Exception e) {
throw new RuntimeException("BINGO, an error");
}
}
private CommonActions(String title, String desc) {
super(title);
putValue(SHORT_DESCRIPTION, desc);
}
public static CommonActions getInstance() {
return commonActions;
}
public static void setValues(JFrame f) {
frame = f;
}
#Override
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(frame,
"Closing Frame", "Information", JOptionPane.INFORMATION_MESSAGE);
frame.dispose();
}
}
I want to create basic JUnit test for JavaFX 8 application. I have this simple code sample:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setText("Tab" + i);
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I only have this code so far:
import javafx.application.Application;
import javafx.stage.Stage;
import org.junit.BeforeClass;
public class BasicStart extends Application {
#BeforeClass
public static void initJFX() {
Thread t = new Thread("JavaFX Init Thread") {
#Override
public void run() {
Application.launch(BasicStart.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
}
#Override
public void start(Stage primaryStage) throws Exception {
// noop
}
}
Can you tell me how I can create JUnit test for the above code?
I use a Junit Rule to run unit tests on the JavaFX thread. The details are in this post. Just copy the class from that post and then add this field to your unit tests.
#Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule();
This code works for both JavaFX 2 and JavaFX 8.
The easiest aproach is the following:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import org.junit.Test;
public class BasicStart {
#Test
public void testA() throws InterruptedException {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
new JFXPanel(); // Initializes the JavaFx Platform
Platform.runLater(new Runnable() {
#Override
public void run() {
new Main().start(new Stage()); // Create and
// initialize
// your app.
}
});
}
});
thread.start();// Initialize the thread
Thread.sleep(10000); // Time to use the app, with out this, the thread
// will be killed before you can tell.
}
}
Hope it helps!
Based on Brian Blonski 's answer I created a JUnit-Testrunner, that does essentially the same thing, but is a bit simpler to use in my opinion.
Using it, your test would look like this:
#RunWith( JfxTestRunner.class )
public class MyUnitTest
{
#Test
public void testMyMethod()
{
//...
}
}
I've made a simple Media Player for an application I'm working on, the problem is that I thought that you could simply integrate JavaFX into Swing. Which is not the case. I have been searching for a solution to this problem and tried to use this website: http://docs.oracle.com/javafx/2/swing/jfxpub-swing.htm
The problem is that even though I have the website that explains how to put the code together, I still don't understand how. Here is the mediaplayer and I plan to integrate it into my Swing code, so that I can call the media player when a button is clicked. Here is all my code for the media player and if anyone can share some light on how to integrate it into my Swing code i.e my GUI, I would probably have to kiss you through the computer.
public class Player extends Application{
private boolean atEndOfMedia = false;
private final boolean repeat = false;
private boolean stopRequested = false;
private Duration duration;
private Label playTime;
private Slider volumeSlider;
#Override
public void start(final Stage stage) throws Exception {
stage.setTitle("Movie Player");//set title
Group root = new Group();//Group for buttons etc
final Media media = new Media("file:///Users/Paul/Downloads/InBruges.mp4");
final MediaPlayer playa = new MediaPlayer(media);
MediaView view = new MediaView(playa);
//Slide in and out and what causes that.
final Timeline slideIn = new Timeline();
final Timeline slideOut = new Timeline();
root.setOnMouseEntered(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(MouseEvent t) {
slideIn.play();
}
});
root.setOnMouseExited(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(MouseEvent t) {
slideOut.play();
}
});
final VBox vbox = new VBox();
final Slider slider = new Slider();
final Button playButton = new Button("|>");
root.getChildren().add(view);
root.getChildren().add(vbox);
vbox.getChildren().add(slider);
vbox.getChildren().add(playButton);
vbox.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 400, 400, Color.BLACK);
stage.setScene(scene);
stage.show();
// Play/Pause Button
playButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
Status status = playa.getStatus();
if (status == Status.UNKNOWN || status == Status.HALTED)
{
// don't do anything in these states
return;
}
if ( status == Status.PAUSED
|| status == Status.READY
|| status == Status.STOPPED)
{
// rewind the movie if we're sitting at the end
if (atEndOfMedia) {
playa.seek(playa.getStartTime());
atEndOfMedia = false;
}
playa.play();
} else {
playa.pause();
}
}
});
//Listeners and Shit for Play Button
playa.setOnPlaying(new Runnable() {
#Override
public void run() {
if (stopRequested) {
playa.pause();
stopRequested = false;
} else {
playButton.setText("||");
}
}
});
playa.setOnPaused(new Runnable() {
#Override
public void run() {
playButton.setText(">");
}
});
playa.play();
playa.setOnReady(new Runnable() {
#Override
public void run(){
int v = playa.getMedia().getWidth();
int h = playa.getMedia().getHeight();
stage.setMinWidth(v);
stage.setMinHeight(h);
vbox.setMinSize(v, 100);
vbox.setTranslateY(h-50);
//slider and graphical slide in/out
slider.setMin(0.0);
slider.setValue(0.0);
slider.setMax(playa.getTotalDuration().toSeconds());
slideOut.getKeyFrames().addAll(
new KeyFrame(new Duration(0),
new KeyValue(vbox.translateYProperty(), h-100),
new KeyValue(vbox.opacityProperty(), 0.9)
),
new KeyFrame(new Duration(300),
new KeyValue(vbox.translateYProperty(), h),
new KeyValue(vbox.opacityProperty(), 0.0)
)
);
slideIn.getKeyFrames().addAll(
new KeyFrame(new Duration(0),
new KeyValue(vbox.translateYProperty(), h),
new KeyValue(vbox.opacityProperty(), 0.0)
),
new KeyFrame(new Duration(300),
new KeyValue(vbox.translateYProperty(), h-100),
new KeyValue(vbox.opacityProperty(), 0.9)
)
);
}
});
//Slider being current and ability to click on slider.
playa.currentTimeProperty().addListener(new ChangeListener<Duration>(){
#Override
public void changed(ObservableValue<? extends Duration> observableValue, Duration duration, Duration current){
slider.setValue(current.toSeconds());
}
});
slider.setOnMouseClicked(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(javafx.scene.input.MouseEvent t) {
playa.seek(Duration.seconds(slider.getValue()));
}
});
}
Use JFXPanel:
public class Test {
private static void initAndShowGUI() {
// This method is invoked on Swing thread
JFrame frame = new JFrame("FX");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setVisible(true);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
}
where method createScene() is start(final Stage stage) from your code.
Just instead of putting scene to stage you return it.