JavaFX - Object with Constructor - constructor

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.

Related

LibGDX - check if compass needs calibration

How to check if compass is calibrated well in LibGDX (on Android). I've found how to do it on native Android:
In Android can I programmatically detect that the compass is not yet calibrated?
But couldn't find if that's implemented in LibGDX.
What you want is described in the wiki article Interfacing with platform specific code. LibGDX doesn't have any functionality for it because it isn't common and it doesn't make any sense for other backends.
In the core module you'll have something like this:
public interface GameListener {
void calibrateCompassIfNeeded()
}
public class Application extends ApplicationAdapter {
private GameListener listener;
public Application(GameListener listener) {
this.listener = listener;
}
#Override
public void create() {
// Call listener.calibrateCompassIfNeeded() whenever needed.
}
public void onCompassChanged(float[] values) {
// Do something...
}
}
And in the android module:
public class AndroidLauncher extends AndroidApplication implements GameListener, SensorEventListener {
private static final int COMPASS_ACCURACY_UNKNOWN = -1;
private Application app;
private int compassAccuracy = COMPASS_ACCURACY_UNKNOWN;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor compassSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sensorManager.registerListener(this, compassSensor, SensorManager.SENSOR_DELAY_GAME)
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
app = new Application(this);
initialize(app, config);
}
#Override
public void calibrateCompassIfNeeded() {
if (compassAccuracy != COMPASS_ACCURACY_UNKNOWN && compassAccuracy < SENSOR_STATUS_ACCURACY_MEDIUM) {
// Calibrate only if accuracy is below medium.
// Show whatever is needed so user calibrates the compass.
}
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
app.onCompassChanged(event.values);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
compassAccuracy = accuracy;
}
}
I haven't tried it and I have never used the compass before but I'm pretty sure this will work fine.

Mocking the object inside the class without PowerMock

I want to mock the object inside the class wihtout using Powermock. How can I do it?
I tried using spy but it didn't work.
/** SOURCE CODE **/
abstract class Parent {
protected final Caller caller = new Caller();
public abstract void call(Connection, Integer);
}
class Child1 extends Parent {
#Override
public void call(Connection con, Integer id1) {
// some logic
caller.getSomething1(connection, id1);
}
}
class Child2 extends Parent {
#Override
public void call(Connection con, Integer id2) {
// some logic
caller.getSomething2(connection, id2);
}
}
class Activity {
#Inject
private MyConnection connection;
public Response process(Request r) {
Parent p = ChildFactory.getChild(r); // returns a child based on some logic related to p
p.call(connection, r.getId());
return new Response("SUCCESS");
}
}
/** TEST CODE **/
public class Test {
#InjectMocks
private Activity activity;
#Mock
private Connection connectionMock;
private Caller caller;
#Before
public void setup() throws Exception {
caller = Mockito.spy(Caller.class);
Mockito.doReturn(null).when(caller).getSomething1(Mockito.any(), Mockito.any());
Mockito.doReturn(null).when(caller).getSomething2(Mockito.any(), Mockito.any());
}
#Test
public void testProcess() {
Request r = new Request(1);
Response r = activity.process(r);
Assert.assertEquals(r.getResult(), "SUCCESS");
}
}
I want to mock the caller object created in Parent class. It is going to be consumed by every children. I am not bothered about the result of the calls so I want to mock all calls (i.e. getSomething1, getSomething2) of callers without use of PowerMock.
I tried using spy but it is not using the spied object and it is calling getSomething1 and getSomething2 methods.
You can use ReflectionTestUtils#setField
#Before
public void setup() throws Exception {
caller = Mockito.spy(Caller.class);
Mockito.doReturn(null).when(caller).getSomething1(Mockito.any(), Mockito.any());
Mockito.doReturn(null).when(caller).getSomething2(Mockito.any(), Mockito.any());
// ... obtain children here ...
ReflectionTestUtils.setField(child1, "caller", caller);
ReflectionTestUtils.setField(child2, "caller", caller);
}
Or better you don't instantiate Caller instance inside Child-classes but inject via constructor for example

JavaFX: can't call a Controller function from anoher class

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.

Basic JUnit test for JavaFX 8

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()
{
//...
}
}

documentFilter.insert never called

I'm trying to set a documentFilter for my JTextArea. Having overriden the insert(...) method I admitted that it is never called. What's wrong? A piece of code:
package jaba;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
public class Main extends JFrame {
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(640, 480);
setLayout(new FlowLayout());
add(txt);
Document doc = txt.getDocument();
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).setDocumentFilter(new DocumentFilter() {
#Override
public void insertString(DocumentFilter.FilterBypass fb,
int offset, String string, AttributeSet att)
throws BadLocationException {
if (string.toLowerCase().contains("ass")) {
super.insertString(fb, offset, "###", att);
} else {
super.insertString(fb, offset, string, att);
}
}
});
} else {
txt.setText("error setting filter");
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main().setVisible(true);
}
});
}
private JTextArea txt = new JTextArea(40, 40);
}
Having overriden the insert(...) method I admitted that it is never called.
Changes to the text in Swing components ultimately invoke the replace(...) method of the DocumentFilter.
The insertString(...) method is only invoked when you update the Document directly by using code like:
textField.getDocument().insertString(...);
So you need to make sure that you also override the replace() method in the DocumentFilter.