How is a non-static method accessed without an object? - javafx-8

I am new to JavaFX. In my following code, getHBox() is a non-static method is accessed without creating an object.
public class Main extends Application {
public void start(Stage primaryStage) {
//Main m = new Main();
try {
BorderPane rootPane = new BorderPane();
rootPane.setTop(getHBox());
//rootPane.setTop(m.getHBox());
Scene scene = new Scene(rootPane,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public HBox getHBox()
{
HBox hb = new HBox(15);
hb.getChildren().add(new Button("Press"));
return hb;
}
public static void main(String[] args) {
launch(args);
}
}
Now I have looked at the answers in Stackoverflow. Guys are talking something about class member. How is getHBox() method different from any other method? Please provide some explanation or direct me to an appropriate tutorial.

In my following code, getHBox() is a non-static method is accessed without creating an object.
That is incorrect. As used in the code presented, getHBox() is invoked only by start(), another non-static method. As an instance method itself, start() must be invoked on an object (one instantiated by JavaFX, for instance). The invocation of getHBox() without designating a target object is implicitly directed to the same object, as if it were this.getHBox().
How is getHBox() method different from any other method?
It isn't, not in any relevant sense, nor is any of this specific to JavaFX.

Related

Autofac, accessing ContainerBuilder from random component

I am playing with Autofac and let's pretend i have a component (DLL) in my application that is using Logging. How and where to log will be defined by main App. So it registers ILog interface with Autofac.
Problem is how my component can get access to ContainerBuilder object to resolve ILog?
I can always initialize my component with IContainer but that defeats the purpose. I would just pass ILog interface to component instead of IContainer.
If I understand where you are with this correctly - it's worth reading up on the "Composition Root" for how to think about this in general. The short answer is "you don't access Containers from components."
https://blog.ploeh.dk/2011/07/28/CompositionRoot/
As you say, your component shouldn't know anything about Autofac - that actually goes for all of your code except a small section in your main application. So how does the ILog find its way to your component? From that Mark Seemann post:
"This means that all the application code relies solely on Constructor Injection"
That's a good general rule to make your code cleaner, even if you weren't using a DI framework. So in your situation, say you have a very simple app like this:
class Program
{
static void Main(string[] args)
{
var component = new Component(); // we want logging to happen inside here
component.DoStuff();
Console.ReadKey();
}
}
You actually just want to add your ILog as a dependency on your Component and then inject that as close as possible to your app-entry point:
public class Component
{
private readonly ILog _logger;
public Component(ILog logger)
{
_logger = logger;
}
public void DoStuff()
{
_logger.Log("this is a test");
}
}
class Program
{
static void Main(string[] args)
{
var container = GetContainer();
using (var scope = container.BeginLifetimeScope())
{
var test = scope.Resolve<Component>(); // this is potentially the only place we need to resolve anything
test.DoStuff();
}
Console.ReadKey();
}
private static IContainer GetContainer()
{
var builder = new ContainerBuilder();
builder.RegisterType<Component>();
builder.RegisterType<Logger>()
.As<ILog>();
var container = builder.Build();
return container;
}
}

NullPointerException when I changed all my methods to static

Using Selenium w Java and Test NG (POM format) Switched everything from not static to static and changed everything accordingly, getting NullPointerException. It worked when everything was not static, but making everything static requires less code so I'd prefer to have it that way.
Here is my code.. while trying to paste my code for some reason it did not recognize the import statements as code so I just did not include them, but rest assured everything has been imported that is needed! :)
Package pages;
public class locationPage {
WebDriver driver;
static #FindBy (id="btn_bogota") WebElement chooseBogota;
static #FindBy (id="btn_medellin") WebElement chooseMedellin;
static #FindBy (xpath="//title") WebElement pageTitle;
public locationPage (WebDriver driver){
this.driver=driver;
PageFactory.initElements(driver, this);
}
public static void chooseLocation (String location) {
if (location.equals("Bogota"))
{
chooseBogota.click();
}
else if (location.equals("Medellin")){
chooseMedellin.click();
}
}
}
Package testcases;
public class selectLocation {
WebDriver driver;
#BeforeClass
public void setup() throws InterruptedException{
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://dev01.juanregala.com.co/");
//Generating Alert Using Javascript Executor
JavascriptExecutor javascript = (JavascriptExecutor) driver;
javascript.executeScript("alert('Select Location');");
Thread.sleep(2000);
driver.switchTo().alert().accept();
}
#AfterTest
public void quit(){
driver.quit();
}
#Test (priority=0)
public void location(){
locationPage.chooseLocation("Medellin");
}
}
It keeps giving me a NullPointerException referring to
chooseMedellin.click();
and
locationPage.chooseLocation("Medellin");
I am not really sure how else to describe my issue :( Please help!
You are getting a NullPointerException because the fields are not initialized. You can't use a page object in this way. Even if you could, you probably wouldn't want to since a page object is tied to a particular web driver and that would mean you could never use the same page object among multiple tests and run them in parallel.
Basically, the PageFactory only works on object instances. It won't initialize static fields and, even if it did, you are only calling the page factory from the constructor of your page and that is never being called since you only call a static method on that class.
You need to create an instance of the page object and then pass it to the PageFactory along with the driver that will be running the page object.
Simple example:
public class FooTest {
private WebDriver driver;
private FooPage page;
#BeforeMethod
public void setup() {
driver = new FirefoxDriver();
page = PageFactory.initElements(driver, FooPage.class);
}
#AfterMethod
public void tearDown() {
try {
driver.quit();
} catch ( Exception ignore ) { }
driver = null;
page = null;
}
#Test
public void testFoo() {
}
}
public class FooPage {
#FindBy(id="foo")
private WebElement fooElement;
public void clickFoo() {
fooElement.click();
}
}
Note the line:
page = PageFactory.initElements(driver, FooPage.class);
That method will actually call the default construct of FooPage. You can also instantiate the object yourself and pass it to the page factory like this:
page = new FooPage();
PageFactory.initElements(driver, page);

How to position controls binding there position into the stage's size using the controller class in JavaFx?

I found some thing similar in this link
How to call functions on the stage in JavaFX's controller file
and here is what I found in one of the answers
StageTrackingSample.java
public class StageTrackingSample extends Application {
#Override public void start(final Stage stage) throws Exception {
final FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"stagetracking.fxml"
)
);
final Parent root = (Parent) loader.load();
final StageTrackingController controller = loader.getController();
controller.initData(stage);
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String[] args) { launch(args); }
}
StageTrackingController.java
public class StageTrackingController {
#FXML private Label stageX;
public void initialize() {}
public void initData(final Stage stage) {
stageX.textProperty().bind(
Bindings.format(
"(%1$.2f, %2$.2f)",
stage.xProperty(),
stage.yProperty()
)
);
}
}
I wanted to position the progressIndicator in the middle of the window, so I tried this in my controller class
Controller.java
public void initInterface(Stage stage) {
progressIndicator.layoutXProperty().bind(stage.widthProperty().divide(2));
progressIndicator.layoutYProperty().bind(stage.heightProperty().divide(2));
}
and this in Main.java
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
final FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
final Parent root = loader.load();
final Controller controller = loader.getController();
final Scene scene = new Scene(root);
controller.initInterface(primaryStage);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
it doesn't work even when I tried passing the scene or the anchorpane(which is defined in the fxml file) as a parameter into initInterface method, it seems that it has problem with binding progressIndicator properties
by using the layoutXProperty and layoutYProperty and binding them to the Stage's width and height you must be trying to put it in the lower right hand corner of the stage. You can achieve this much easier, and JavaFX insists you do so, by using layouts in your scene and making the scene fill the entire area in question.
"From the Javadocs for the layoutX property:
If the node is managed and has a Region as its parent, then the layout region will set layoutX according to its own layout policy. If the node is unmanaged or parented by a Group, then the application may set layoutX directly to position it.
What this means is that the LayoutX/Y properties are controlled by the parent (and so it should be able to 'set' them). However, when you bind them they cannot be set anymore resulting in " A bound value cannot be set" exception."
Here is a good tutorial on regions and how to get things to layout in SceneBuilder as you please. If you're not using SceneBuilder I recommend it.
https://www.youtube.com/watch?v=zvgWgpGZVKc&list=PL6gx4Cwl9DGBzfXLWLSYVy8EbTdpGbUIG&index=35

JavaFX: How to update the center view of a borderpane with new values

I am creating a program which has a row of buttons on the top, and a row of buttons on the side.
The top buttons control the view, and the side buttons control what object to reference in the view.
My main/root view is a borderpane.
The point is to, as I click on any of these buttons, to change a value in my MainController, and then reload the center view with these new values. I thought it would be so simple as to write a method that would change the value and then set a new center according to these values.
However, as I test it, it can display the two values I have already asked it to display, but gives me a huge load of red error code whenever I run.
My MainViewController looks as follows:
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class MainViewController extends Application {
#FXML
private Button cabin1;
#FXML
private Button cabin2;
#FXML
private Button tab1;
#FXML
private Button tab2;
#FXML
public void setCabinOne() throws IOException {
cabinIndex=1;
setCenterView();
}
#FXML
public void setCabinTwo() throws IOException {
cabinIndex=2;
setCenterView();
}
#FXML
public void setTabOne() throws IOException {
tabIndex=1;
setCenterView();
}
#FXML
public void setTabTwo() throws IOException {
tabIndex=2;
setCenterView();
}
public int getCabinIndex() {
return cabinIndex;
}
public int getTabIndex() {
return tabIndex;
}
private int tabIndex=0;
private int cabinIndex=1;
public Stage primaryStage;
private BorderPane mainPane;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage=primaryStage;
primaryStage.setTitle("Test");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainViewController.class.getResource("MainView.fxml"));
mainPane = loader.load();
setCenterView();
Scene scene = new Scene(mainPane);
primaryStage.setScene(scene);
primaryStage.show();
}
public void setCenterView() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainViewController.class.getResource("TestView.fxml"));
AnchorPane testPane = loader.load();
TestViewController tvc = loader.<TestViewController>getController();
tvc.changeLabel(getCabinIndex());
tvc.changeIndex(getTabIndex());
mainPane.setCenter(testPane);
}
}
and my TestViewController looks as follows:
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class TestViewController {
#FXML
private Label cabinIndex;
#FXML
private Label tabIndex;
public void initialise() {
this.changeLabel(0);
this.changeIndex(0);
}
public void changeLabel(int n) {
cabinIndex.setText("Cabin "+Integer.toString(n));
}
public void changeIndex(int n) {
tabIndex.setText("Tab "+Integer.toString(n));
}
}
What am I doing wrong?
Your application is basically structurally wrong: you are using the application subclass as the controller, and this simply won't work (at least, not easily). You need to refactor this with a startup class (subclass of Application) that is distinct from the controller. Virtually any complete example will work as a template for you, but the Oracle tutorial is a good place to start.
What is happening is as follows:
When you call Application.launch() in MainViewController.main(...), the FX toolkit is started, an instance of your application class MainViewController is created, the FX Application Thread is started, and the start() method belonging to the MainViewController instance is invoked on the FX Application Thread.
When you call the FXMLLoader's load() method, it parses the FXML file at the specified location. When it sees the fx:controller attribute, which I'm assuming is fx:controller="MainViewController", it creates an instance of the specified controller class. Once the FXML is parsed, any matching #FXML-annotated fields (belonging to that instance) are initialized with the corresponding objects from the FXML file, and then the initialize() method is called on that instance.
So notice now you actually have two instances of MainViewController: the one from which FXMLLoader.load() was called, and the one created by the FXMLLoader. The #FXML-annotated fields in the instance created by the FXMLLoader are initialized, but the ones in the original instance remain set to the default value of null. Conversely, the mainPane field is initialized in the start method in the original MainViewController instance, but is never initialized in the instance created by the FXMLLoader. So when you press the button and invoke setCenterView() (I assume this is how your FXML is set up), you end up calling mainPane.setCenter() when mainPane is still null.
You could probably just about force it to work like this. Something like: remove the fx:controller attribute from MainView.fxml, and call loader.setController(this). But when you stray that far from the usual patterns used by a framework, your code becomes hard to maintain and debug. I would recommend following the design intended by the API.

Adding Action Listeners at Netbeans

I have a Jbutton added on a frame automaticaly by netbeans.
I want to add this Actionlistener to a button.
public class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,"hello");
}
My problem is that when I add this code
jButton2.addActionListener(MyActionListener);
in order to add the listener to the button I get a "non-static variable jButton2 cannot be referenced from a static context" message.
Since jButton2 is automatically created by netbeans as non static, how can overcome this problem and set the actionlistener as I want?
The error lies in that you are sending an object that has never been instantiated. When you add an action listener to any component you need to send an object that implements the ActionListener interface. Is like adding an instance of the listener to the object.
try this:
jButton2.addActionListener(new MyActionListener());
if you want to use an Anonymous implementation then you will do:
jButton2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//some code
}
});
An easy way to add a listener is just to right-click on the button from the design view, select
Events -> Action -> actionPerformed
and the code will be auto-generated for you
public void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// put what you want to happen, here
}