JavaFX Mouse Event Registration And Propagation
This is an examination of registering InputEvents, in this case MouseEvents (clicked), Event propagation, and how the registered methods are called in response to the Event propagation.
The code can be cloned from github.com as before. The link is https://github.com/cajanssen/JavaFXMouseEventRegistration.git Refer to earlier postings for advice on how to bring a GitHub project into Eclipse.
The JavaFX user interface, like many other user interface frameworks, is built upon a nested tree of user interface objects. (JavaFX uses the term "scene graph".) In the JavaFX case, it is the scene graph is a collection of Node objects. Note that the "root" Node ("root" being the top of the content tree) actually needs to be a Parent, which is a direct subclass of Node. (Stage -> Scene -> Parent -> many Node(s)) The Stage is the equivalent of a window, and if more than one window is desired for an application, additional Stage objects must be created.
https://openjfx.io/javadoc/13/javafx.graphics/javafx/stage/Stage.html
https://openjfx.io/javadoc/13/javafx.graphics/javafx/scene/Scene.html
https://openjfx.io/javadoc/13/javafx.graphics/javafx/scene/Node.html
https://openjfx.io/javadoc/13/javafx.graphics/javafx/scene/Parent.html
Note that, as evidenced by the URL, the documentation links point to a specific version of JavaFX (i.e., 13). So, depending upon how Gluon maintains the documentation over time, these links may eventually break. Currently, links back through version 11 are active.
Since this user interface is a nested tree, user interface events will occur within the visual bounding area of more than one object (i.e. the topmost object, its parent, its grandparent, etc.). These events will propagate through the tree (scene graph) such that all the relevant objects have a chance at reacting to them. The user interface objects can have EventHandler objects attached to them in two ways: via Event filters and via Event handlers. The difference between these two is when they execute. Events propagate down the tree from the top in what is called the capturing phase. Event filters are called during this time. When the bottom of the tree is reached, the Event propagates back up the tree in what is called the bubbling phase. Event handlers are called during this time. Event propagation can be halted at any time by calling consume() on the actual Event in the handler code. (In the code below, e.consume() in the handle() method of one of the EventHandler objects.)
Example code:
package jansproj.basicfx;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MouseEventRegistration extends Application
{
public MouseEventRegistration()
{
}
// this application waits for and reacts to mouse click events
@Override
public void start(Stage stage) throws Exception
{
// Stage, Scene, root Node - standard stuff common to JavaFX programs
stage.setTitle("Mouse Event Example");
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
int canvasWidth = 1000;
int canvasHeight = 500;
int canvasXCenter = canvasWidth / 2;
int canvasYCenter = canvasHeight / 2;
Canvas canvas = new Canvas(canvasWidth, canvasHeight);
// rather than create a large tree of nodes, create a tree of only
// one node - canvas - and draw on that
Group extraGroup = new Group();
extraGroup.getChildren().add(canvas);
root.getChildren().add(extraGroup);
double blackCircleRadius = 250;
double blueCircleRadius = 200;
double redCircleRadius = 150;
double goldCircleRadius = 100;
// make concentric circles
// drawing point for strokeOval() is the upper left corner of bounding box, not the center
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(4.0);
gc.setStroke(Color.BLACK);
gc.strokeOval((canvasXCenter - blackCircleRadius), (canvasYCenter - blackCircleRadius), blackCircleRadius*2, blackCircleRadius*2);
gc.setStroke(Color.BLUE);
gc.strokeOval((canvasXCenter - blueCircleRadius), (canvasYCenter - blueCircleRadius), blueCircleRadius*2, blueCircleRadius*2);
gc.setStroke(Color.RED);
gc.strokeOval((canvasXCenter - redCircleRadius), (canvasYCenter - redCircleRadius), redCircleRadius*2, redCircleRadius*2);
gc.setStroke(Color.GOLD);
gc.strokeOval((canvasXCenter - goldCircleRadius), (canvasYCenter - goldCircleRadius), goldCircleRadius*2, goldCircleRadius*2);
// attach a Mouse Click event handler to the scene
// rather than create the object elsewhere and pass it in to the setOnMouseClicked()
// method, define the event handler right here with
// an anonymous inner class - common practice
scene.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Scene event handler (via set)"); }
});
root.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Root (Group) event handler (via set)"); e.consume();}
});
extraGroup.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event handler (via set) #1"); }
});
extraGroup.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event handler (via set) #2"); }
});
extraGroup.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event handler #1 (via add)"); }
});
extraGroup.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event handler #2 (via add)"); }
});
extraGroup.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event handler #3 (via add)"); }
});
canvas.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Canvas event handler (via set)"); }
});
scene.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Scene event filter #1"); };
});
scene.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Scene event filter #2"); }
});
scene.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Scene event filter #3"); };
});
root.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Root (Group) event filter"); }
});
extraGroup.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("ExtraGroup event filter"); }
});
canvas.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{ System.out.println("Canvas event filter"); }
});
// calling show() on the Stage is a standard requirement for a JavaFX program
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
Note that due to the redundancy in this code, it is compressed and formatted less explicitly than might be expected.
Also note that the second Group object, named "extraGroup" in the code, is gratuitous and is only in the code to add depth to the user interface object tree to better display the propagation of events.
During the execution of the application, the mouse clicks will cause each EventHandler object to print to the console an identification of itself, providing a listing of the order in which they executed.
Event filters (EventHandler objects) to be executed during the capture phase are added via the addEventFilter() method. Note that multiple event filters can be added to each Node type object. Also, it would appear filters execute in order added. However, it is not specified as such in the documentation. Therefore, it would be prudent not to assume that to be guaranteed behavior. Even if an examination of the source for the framework libraries did show this to be true, if it is not specified in the interface contract (and written in the documentation somewhere) it could change at any time in the future as library components are updated.
Event handlers (again, EventHandler objects) to be executed during the bubbling phase can be added in two ways - with the setOnMouseClicked method (name of the method depends upon event being handled) and the addEventHandler method (type of the event passed as a parameter). As can be see in examining and executing the example code, only one handler can be added with setOnMouseClicked(). Any subsequent calls on the same Node (or descendant) object overwrites the first handler. Multiple handlers can be added with addEventHandler(). Also as is seen in the example code, calls to setOnMouseClicked() and addEventHandler() do not interfere with each other.
Finally, note that during execution two of the created handler objects never get called. The first, "ExtraGroup event handler #1", because another setOnMouseClicked called overwrote the first handler. (As mentioned above.) For the second, "Scene event handler", e.consume() is called in the root Event handler and stops propagation before it makes it back up to the top. The handler "Scene event handler" would have been called at the very end.
Friday, November 1, 2019
Tuesday, October 22, 2019
Basic JavaFX projects (Part 2)
JavaFX Mouse Event Example
Here is an example of capturing mouse events in JavaFX.
Clone this repository into Eclipse as was specified in a previous post. (Git Repository view, clone a Git Repository). The URI is https://github.com/cajanssen/JavaFXMouseEvent.git
After the project is created, as before (previous post) do some JavaFX project specific configuration in Eclipse. (Add the already created user library and modify the Run configuration.)
Javadocs for JavaFX classes: https://openjfx.io/javadoc/13/allclasses-index.html
Code:
package jansproj.basicfx;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MouseEventExample extends Application
{
public MouseEventExample()
{
}
// this application waits for and reacts to mouse click events
@Override
public void start(Stage stage) throws Exception
{
// Stage, Scene, root Node - standard stuff common to JavaFX programs
stage.setTitle("Mouse Event Example");
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
int canvasWidth = 1000;
int canvasHeight = 500;
int canvasXCenter = canvasWidth / 2;
int canvasYCenter = canvasHeight / 2;
Canvas canvas = new Canvas(canvasWidth, canvasHeight);
// rather than create a large tree of nodes, create a tree of only
// one node - canvas - and draw on that
root.getChildren().add(canvas);
double blackCircleRadius = 250;
double blueCircleRadius = 200;
double redCircleRadius = 150;
double goldCircleRadius = 100;
// make concentric circles
// drawing point for strokeOval() is the upper left corner of bounding box, not the center
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(4.0);
gc.setStroke(Color.BLACK);
gc.strokeOval((canvasXCenter - blackCircleRadius), (canvasYCenter - blackCircleRadius), blackCircleRadius*2, blackCircleRadius*2);
gc.setStroke(Color.BLUE);
gc.strokeOval((canvasXCenter - blueCircleRadius), (canvasYCenter - blueCircleRadius), blueCircleRadius*2, blueCircleRadius*2);
gc.setStroke(Color.RED);
gc.strokeOval((canvasXCenter - redCircleRadius), (canvasYCenter - redCircleRadius), redCircleRadius*2, redCircleRadius*2);
gc.setStroke(Color.GOLD);
gc.strokeOval((canvasXCenter - goldCircleRadius), (canvasYCenter - goldCircleRadius), goldCircleRadius*2, goldCircleRadius*2);
// attach a Mouse Click event handler to the scene
// rather than create the object elsewhere and pass it in to the setOnMouseClicked()
// method, define the event handler right here with
// an anonymous inner class - common practice
scene.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{
System.out.println("x= " + e.getX() + " y= " + e.getY());
double distance = Math.sqrt(((canvasXCenter - e.getX()) * (canvasXCenter - e.getX())) + (canvasYCenter - e.getY()) *(canvasYCenter - e.getY()));
String location = "outside";
if ( distance < blackCircleRadius )
location = "black circle";
if ( distance < blueCircleRadius )
location = "blue circle";
if ( distance < redCircleRadius )
location = "red circle";
if ( distance < goldCircleRadius )
location = "gold circle";
System.out.println(location);
}
});
// calling show() on the Stage is a standard requirement for a JavaFX program
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
The tree of Nodes to be displayed is different than the previous example. Instead of nesting multiple Node type objects within each other (FlowPane, Label, Button), there is only one Node object in the tree - Canvas - and all the drawing is done on that Node using GraphicsContext drawing method calls.
The application draws some concentric circles on the Canvas at known distances from the center. These distances are then used by the MouseEvent EventHandler to determine where in the collection of circles the mouse click occurred.
Here is an example of capturing mouse events in JavaFX.
Clone this repository into Eclipse as was specified in a previous post. (Git Repository view, clone a Git Repository). The URI is https://github.com/cajanssen/JavaFXMouseEvent.git
After the project is created, as before (previous post) do some JavaFX project specific configuration in Eclipse. (Add the already created user library and modify the Run configuration.)
Javadocs for JavaFX classes: https://openjfx.io/javadoc/13/allclasses-index.html
Code:
package jansproj.basicfx;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MouseEventExample extends Application
{
public MouseEventExample()
{
}
// this application waits for and reacts to mouse click events
@Override
public void start(Stage stage) throws Exception
{
// Stage, Scene, root Node - standard stuff common to JavaFX programs
stage.setTitle("Mouse Event Example");
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
int canvasWidth = 1000;
int canvasHeight = 500;
int canvasXCenter = canvasWidth / 2;
int canvasYCenter = canvasHeight / 2;
Canvas canvas = new Canvas(canvasWidth, canvasHeight);
// rather than create a large tree of nodes, create a tree of only
// one node - canvas - and draw on that
root.getChildren().add(canvas);
double blackCircleRadius = 250;
double blueCircleRadius = 200;
double redCircleRadius = 150;
double goldCircleRadius = 100;
// make concentric circles
// drawing point for strokeOval() is the upper left corner of bounding box, not the center
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(4.0);
gc.setStroke(Color.BLACK);
gc.strokeOval((canvasXCenter - blackCircleRadius), (canvasYCenter - blackCircleRadius), blackCircleRadius*2, blackCircleRadius*2);
gc.setStroke(Color.BLUE);
gc.strokeOval((canvasXCenter - blueCircleRadius), (canvasYCenter - blueCircleRadius), blueCircleRadius*2, blueCircleRadius*2);
gc.setStroke(Color.RED);
gc.strokeOval((canvasXCenter - redCircleRadius), (canvasYCenter - redCircleRadius), redCircleRadius*2, redCircleRadius*2);
gc.setStroke(Color.GOLD);
gc.strokeOval((canvasXCenter - goldCircleRadius), (canvasYCenter - goldCircleRadius), goldCircleRadius*2, goldCircleRadius*2);
// attach a Mouse Click event handler to the scene
// rather than create the object elsewhere and pass it in to the setOnMouseClicked()
// method, define the event handler right here with
// an anonymous inner class - common practice
scene.setOnMouseClicked(
new EventHandler<MouseEvent>()
{
public void handle(MouseEvent e)
{
System.out.println("x= " + e.getX() + " y= " + e.getY());
double distance = Math.sqrt(((canvasXCenter - e.getX()) * (canvasXCenter - e.getX())) + (canvasYCenter - e.getY()) *(canvasYCenter - e.getY()));
String location = "outside";
if ( distance < blackCircleRadius )
location = "black circle";
if ( distance < blueCircleRadius )
location = "blue circle";
if ( distance < redCircleRadius )
location = "red circle";
if ( distance < goldCircleRadius )
location = "gold circle";
System.out.println(location);
}
});
// calling show() on the Stage is a standard requirement for a JavaFX program
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
The tree of Nodes to be displayed is different than the previous example. Instead of nesting multiple Node type objects within each other (FlowPane, Label, Button), there is only one Node object in the tree - Canvas - and all the drawing is done on that Node using GraphicsContext drawing method calls.
The application draws some concentric circles on the Canvas at known distances from the center. These distances are then used by the MouseEvent EventHandler to determine where in the collection of circles the mouse click occurred.
Monday, October 14, 2019
Basic JavaFX projects (Part 1)
This is the first of some basic JavaFX example applications.
JavaFx example with normal window controls.
This example is a simple application that includes some standard controls such as Labels and Buttons. It creates two windows, places several text Labels in one and adds a Button that will remove one of the text Labels.
Clone this repository into Eclipse as was specified in a previous post. (Git Repository view, clone a Git Repository). The URI is https://github.com/cajanssen/TwoWindowLabelList.git
After the project is created, as before (previous post) do some JavaFX project specific configuration. Add the already created user library and modify the Run configuration.
Javadocs for JavaFX classes: https://openjfx.io/javadoc/13/allclasses-index.html
Application code:
package jansproj.basicfx;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class TwoWindowLabelList extends Application
{
public void init() throws Exception
{
System.out.println("init called");
}
@Override
public void start(Stage stage) throws Exception
{
stage.setTitle("JavaFX ThreeApp");
FlowPane root = new FlowPane(Orientation.VERTICAL);
Label label1 = new Label("First Label");
Label label2 = new Label("Second Label");
Label label3 = new Label("Third Label");
Label label4 = new Label("Fourth Label");
Label label5 = new Label("Fifth Label");
Label label6 = new Label("Sixth Label");
Button button1 = new Button("Remove");
button1.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent event)
{
System.out.println("button pressed");
System.out.println(event.getTarget().toString());
root.getChildren().remove(label1);
}
});
root.getChildren().add(button1);
root.getChildren().add(label1);
root.getChildren().add(label2);
root.getChildren().add(label3);
root.getChildren().addAll(label4,label5,label6);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
FlowPane secondRoot = new FlowPane(Orientation.VERTICAL);
Label secondLabel = new Label("Second Window Label");
secondRoot.getChildren().add(secondLabel);
Scene secondScene = new Scene(secondRoot, 200, 400);
Stage secondStage = new Stage();
secondStage.setScene(secondScene);
secondStage.setX(10);
secondStage.setY(10);
secondStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
The first Stage (essentially the window that the application is contained within) is created by the system and handed to the application. An additional window can be created by the application by creating an additional Stage, along with a corresponding Scene and content graph. The Scene needs a Node of type Parent as the root of the content graph. These items are kind of boilerplate. Note that the root(s) in this application are of type FlowPane, whereas in the previous JavaFX example it was a simple Group object. The FlowPane provides for some layout to be done.
The Button has an anonymous inner class for its event handler, a fairly common technique. When pressed, it prints to the command line and removes one of the Labels added to the FlowPane, although it only can do the removal once since after the first time there is no matching object in the List.
JavaFx example with normal window controls.
This example is a simple application that includes some standard controls such as Labels and Buttons. It creates two windows, places several text Labels in one and adds a Button that will remove one of the text Labels.
Clone this repository into Eclipse as was specified in a previous post. (Git Repository view, clone a Git Repository). The URI is https://github.com/cajanssen/TwoWindowLabelList.git
After the project is created, as before (previous post) do some JavaFX project specific configuration. Add the already created user library and modify the Run configuration.
Javadocs for JavaFX classes: https://openjfx.io/javadoc/13/allclasses-index.html
Application code:
package jansproj.basicfx;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class TwoWindowLabelList extends Application
{
public void init() throws Exception
{
System.out.println("init called");
}
@Override
public void start(Stage stage) throws Exception
{
stage.setTitle("JavaFX ThreeApp");
FlowPane root = new FlowPane(Orientation.VERTICAL);
Label label1 = new Label("First Label");
Label label2 = new Label("Second Label");
Label label3 = new Label("Third Label");
Label label4 = new Label("Fourth Label");
Label label5 = new Label("Fifth Label");
Label label6 = new Label("Sixth Label");
Button button1 = new Button("Remove");
button1.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent event)
{
System.out.println("button pressed");
System.out.println(event.getTarget().toString());
root.getChildren().remove(label1);
}
});
root.getChildren().add(button1);
root.getChildren().add(label1);
root.getChildren().add(label2);
root.getChildren().add(label3);
root.getChildren().addAll(label4,label5,label6);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
FlowPane secondRoot = new FlowPane(Orientation.VERTICAL);
Label secondLabel = new Label("Second Window Label");
secondRoot.getChildren().add(secondLabel);
Scene secondScene = new Scene(secondRoot, 200, 400);
Stage secondStage = new Stage();
secondStage.setScene(secondScene);
secondStage.setX(10);
secondStage.setY(10);
secondStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
The first Stage (essentially the window that the application is contained within) is created by the system and handed to the application. An additional window can be created by the application by creating an additional Stage, along with a corresponding Scene and content graph. The Scene needs a Node of type Parent as the root of the content graph. These items are kind of boilerplate. Note that the root(s) in this application are of type FlowPane, whereas in the previous JavaFX example it was a simple Group object. The FlowPane provides for some layout to be done.
The Button has an anonymous inner class for its event handler, a fairly common technique. When pressed, it prints to the command line and removes one of the Labels added to the FlowPane, although it only can do the removal once since after the first time there is no matching object in the List.
Monday, August 26, 2019
Using Git, JavaFX and downloading projects from GitHub into Eclipse
Git is a distributed version control system that currently is widely used. It is distributed in that it can work in a peer-to-peer fashion, rather than needing to synchronize with a central server.
https://git-scm.com/
https://en.wikipedia.org/wiki/Git
Note that Git is a system (or protocol, depending upon how you define it), rather than a specific piece of software. Meaning, that while a client can be downloaded from the above location, there are other clients available, including the one built into Eclipse.
GitHub (https://github.com/) is a site where people can host their projects. Projects hosted here can be public or private.
Obviously Git has a number of commands that support its workflow, but the simplest one to understand and the one that is most useful immediately is “clone”. This does what the name implies, make a copy of a repository.
Basic Java project
Open up the Git Repository view within Eclipse. This is done via Window->Show View->Other->Git->Git Repositories . This should open a pane in the lower left corner of the Eclipse window, under Package Explorer. Since no repositories have yet been added, there should be three links in this view: "Add an existing local Git repository", "Clone a Git repository", "Create a new local Git repository". There are also icons across the top of this view, three of which perform the same functions as the links. (If a repository has been added to this view, the links will be gone, replaced by the repository list and just the icons will remain.)
Click on "Clone a Git repository". This should pop up a dialog box. In the URI field, enter "https://github.com/cajanssen/basictext.git" (without the quotes). This will autofill the Host and Repository path fields. Click Next. The Branch Selection dialog comes up. Master should already be selected, if not select it. Click Next. The Local Destination dialog comes up. The default local directory for the repository is likely C:\Users\<windowsusername>\git\basictext , which should be fine. In the Projects section of this dialog box, check “Import all existing Eclipse projects after the clone finishes”. This will create the project in Package Explorer as well. Click Finish.
This should have added a repository to the Git Repositories view named basictext. It should also have added a project in the Package Explorer. Click on the new project in Package Explorer. In the menus, click on the Run->Run As->Java Application . (This functionality can also be accessed by Right Clicking on the project name in the Package Explorer.) This should run the project which simply outputs two lines of text to the Console window.
JavaFX project
Since Oracle moved JavaFX into a library separate from the base JRE / JDK in version 9 and beyond, there are some additional steps to do to build and run JavaFX projects in Eclipse. This includes projects that are downloaded from a Git repository. Unfortunately, part of this will need to be done individually for each project.
Configure the Eclipse build environment to include JavaFX.
Assumption here is that the JavaFX SDK has already been downloaded, unpacked and placed in an appropriate directory on the local machine. We will be roughly following the instructions that are here: https://openjfx.io/openjfx-docs/ after clicking the "JavaFX and Eclipse" link on the left side. Following the instructions for "Non-modular projects":
1)Create a new User Library via Window->Preferences->Java->Build Path->User Libraries. (You may need to click on the leading “>” on Build Path to get the Build Path subtree to display.) In the User Libraries area, click New... Give the library a name, such as JavaFX11. Click Ok. With that newly created library selected, click Add External JARs... Navigate to the JavaFX SDK lib directory and add the eight JAR files that are there. Click Apply and Close. This User Library is now available to be added to project build paths.
The next steps will need to be done for each project. Therefore, let's pull down another project from Github to work with. This project will include JavaFX functionality. In the Git Repositories view in Eclipse, click the "Clone a Git Repository" icon. This time, enter "https://github.com/cajanssen/basicFXOne.git" (without the quotes). It should work similar to the clone procedure above.
2)Add the newly created user library to the project build path. This would need to be done for JavaFX projects whether they were pulled down via Git or if they were created locally. Select the new project in the Package Explorer and go to Project->Properties->Java Build Path, Libraries tab. Select Classpath in the list and this will cause the buttons on the right to become active. Select Add Library... Select User Library, click Next, select the created library (whatever you named it, probably JavaFX11). Click Finish. Click Apply and Close in the previous dialog box.
3)Run this downloaded project. As above, this can be done by selecting the BasicJavaFXOne project in the Package Explorer and then selecting the command Run->Run As->Java Application. It will likely need you to select the correct application from between a choice of two in the next dialog box. Select the BasicJavaFXOne application. Running the project will result in an error shown in the Console window.
Error: JavaFX runtime components are missing, and are required to run this application
However, Eclipse will have auto-created a new Run Configuration named BasicJavaFXOne that can now be modified specifically for the new project. There is a runtime modification that must be made to include the JavaFX library. Go to Run->Run Configurations... Select the new configuration BasicJavaFXOne. Select the "(x)= Arguments" tab. In the "VM arguments" box, something similar to the following text needs to be added
--module-path "\path\to\javafx-sdk-12.0.2\lib" --add-modules javafx.controls,javafx.fxml
(This text is taken from the openjfx.io page referenced above.) This must be modified, however, to something local to your machine. Specifically, the \path\to\javafx-sdk-12.0.2 portion should be custom, such as
--module-path "C:\Program Files\Java\javafx-sdk-11.0.2\lib" --add-modules javafx.controls,javafx.fxml
Click Apply. You can now run this application with this run configuration with the Run button. The result should be a window popping up in the middle of the screen containing a filled in black circle.
https://git-scm.com/
https://en.wikipedia.org/wiki/Git
Note that Git is a system (or protocol, depending upon how you define it), rather than a specific piece of software. Meaning, that while a client can be downloaded from the above location, there are other clients available, including the one built into Eclipse.
GitHub (https://github.com/) is a site where people can host their projects. Projects hosted here can be public or private.
Obviously Git has a number of commands that support its workflow, but the simplest one to understand and the one that is most useful immediately is “clone”. This does what the name implies, make a copy of a repository.
Basic Java project
Open up the Git Repository view within Eclipse. This is done via Window->Show View->Other->Git->Git Repositories . This should open a pane in the lower left corner of the Eclipse window, under Package Explorer. Since no repositories have yet been added, there should be three links in this view: "Add an existing local Git repository", "Clone a Git repository", "Create a new local Git repository". There are also icons across the top of this view, three of which perform the same functions as the links. (If a repository has been added to this view, the links will be gone, replaced by the repository list and just the icons will remain.)
Click on "Clone a Git repository". This should pop up a dialog box. In the URI field, enter "https://github.com/cajanssen/basictext.git" (without the quotes). This will autofill the Host and Repository path fields. Click Next. The Branch Selection dialog comes up. Master should already be selected, if not select it. Click Next. The Local Destination dialog comes up. The default local directory for the repository is likely C:\Users\<windowsusername>\git\basictext , which should be fine. In the Projects section of this dialog box, check “Import all existing Eclipse projects after the clone finishes”. This will create the project in Package Explorer as well. Click Finish.
This should have added a repository to the Git Repositories view named basictext. It should also have added a project in the Package Explorer. Click on the new project in Package Explorer. In the menus, click on the Run->Run As->Java Application . (This functionality can also be accessed by Right Clicking on the project name in the Package Explorer.) This should run the project which simply outputs two lines of text to the Console window.
JavaFX project
Since Oracle moved JavaFX into a library separate from the base JRE / JDK in version 9 and beyond, there are some additional steps to do to build and run JavaFX projects in Eclipse. This includes projects that are downloaded from a Git repository. Unfortunately, part of this will need to be done individually for each project.
Configure the Eclipse build environment to include JavaFX.
Assumption here is that the JavaFX SDK has already been downloaded, unpacked and placed in an appropriate directory on the local machine. We will be roughly following the instructions that are here: https://openjfx.io/openjfx-docs/ after clicking the "JavaFX and Eclipse" link on the left side. Following the instructions for "Non-modular projects":
1)Create a new User Library via Window->Preferences->Java->Build Path->User Libraries. (You may need to click on the leading “>” on Build Path to get the Build Path subtree to display.) In the User Libraries area, click New... Give the library a name, such as JavaFX11. Click Ok. With that newly created library selected, click Add External JARs... Navigate to the JavaFX SDK lib directory and add the eight JAR files that are there. Click Apply and Close. This User Library is now available to be added to project build paths.
The next steps will need to be done for each project. Therefore, let's pull down another project from Github to work with. This project will include JavaFX functionality. In the Git Repositories view in Eclipse, click the "Clone a Git Repository" icon. This time, enter "https://github.com/cajanssen/basicFXOne.git" (without the quotes). It should work similar to the clone procedure above.
2)Add the newly created user library to the project build path. This would need to be done for JavaFX projects whether they were pulled down via Git or if they were created locally. Select the new project in the Package Explorer and go to Project->Properties->Java Build Path, Libraries tab. Select Classpath in the list and this will cause the buttons on the right to become active. Select Add Library... Select User Library, click Next, select the created library (whatever you named it, probably JavaFX11). Click Finish. Click Apply and Close in the previous dialog box.
3)Run this downloaded project. As above, this can be done by selecting the BasicJavaFXOne project in the Package Explorer and then selecting the command Run->Run As->Java Application. It will likely need you to select the correct application from between a choice of two in the next dialog box. Select the BasicJavaFXOne application. Running the project will result in an error shown in the Console window.
Error: JavaFX runtime components are missing, and are required to run this application
However, Eclipse will have auto-created a new Run Configuration named BasicJavaFXOne that can now be modified specifically for the new project. There is a runtime modification that must be made to include the JavaFX library. Go to Run->Run Configurations... Select the new configuration BasicJavaFXOne. Select the "(x)= Arguments" tab. In the "VM arguments" box, something similar to the following text needs to be added
--module-path "\path\to\javafx-sdk-12.0.2\lib" --add-modules javafx.controls,javafx.fxml
(This text is taken from the openjfx.io page referenced above.) This must be modified, however, to something local to your machine. Specifically, the \path\to\javafx-sdk-12.0.2 portion should be custom, such as
--module-path "C:\Program Files\Java\javafx-sdk-11.0.2\lib" --add-modules javafx.controls,javafx.fxml
Click Apply. You can now run this application with this run configuration with the Run button. The result should be a window popping up in the middle of the screen containing a filled in black circle.
Sunday, August 11, 2019
Installing WMware Workstation and an Xubuntu virtual machine
VMware Workstation Player installation
Installation of VMware Workstation Player is pretty straight forward. Download the program from https://www.vmware.com/ . At that site, navigate to Products->Personal Desktop->Workstation Player which will land you at https://www.vmware.com/products/workstation-player.html . Click the Download Now button and get VMware Workstation 15.1.0 Player for Windows 64-bit Operating Systems. Run the installation executable.
Xubuntu download
Xubuntu is one of the official flavors of Ubuntu. It uses the Xfce desktop. (An official flavor of Ubuntu uses the full Ubuntu archive for packages and updates and is on the same development and release cycle as main Ubuntu. https://ubuntu.com/download/flavours ) Download the installation image from https://xubuntu.org/ . Get the latest LTS (Long Term Support) version, currently 18.04 Bionic Beaver. The LTS versions have maintenance updates for essentially five years. LTS versions are released every two years in April (14.04, 16.04, 18.04). An estimated 95% of Ubuntu installations are LTS releases. https://ubuntu.com/about/release-cycle On the download page, follow the link to the United States mirror. Get the latest 64 bit iso - xubuntu-18.04.3-desktop-amd64.iso - as of this writing. The file size is 1.4 GiB.
Run VMware Workstation
Run VMware Workstation Player and select Create a New Virtual Machine. Choose Installer disc image file (iso) and select the downloaded .iso file. Store the virtual disk as one file. The default 20GB should be big enough for a test system. Click the Customize Hardware... button when you get to the settings screen. Change the memory allocated to the virtual machine to at least 4GB. 6GB (6144 MB) is better on a system with 16GB of physical RAM installed. Increase the number of processors allocated to the virtual machine to at least 2. These hardware options can be changed each time the virtual machine is powered on. When the virtual machine powers on, choose Download VMware Tools for Linux. The VMware window can be resized once it is started up.
Friday, August 9, 2019
Installing Java, Eclipse and JavaFX
Note that in these instructions, something in angle
brackets, such as <javadirectory>, is a placeholder for a value that can
vary.
Installing Java
There are variations on implementation of a Java Development
Kit (JDK). Even more numerous are
variations on Java Virtual Machine (JVM) implementation. However, the main two to consider here are
Oracle JDK and OpenJDK. With respect to
functionality, they are currently pretty much the same:
"From Java 11 forward, therefore, Oracle JDK builds and
OpenJDK builds will be essentially identical." - https://blogs.oracle.com/java-platform-group/oracle-jdk-releases-for-java-11-and-later
Getting the Oracle JDK involves having or creating a free
account at Oracle and logging in before downloading. Getting the OpenJDK has less friction so that
is recommended. https://openjdk.java.net/ will point to https://jdk.java.net/12/ to get version
12. Previous versions will work, but
might as well get the most recent stable version as it seems that the support
cycle is now shorter than before. Oracle
does have their Version 11 as a Long Term Support (LTS) version, but that seems
to be only for a commercial license.
1—Download the OpenJDK.
Downloading from the above location is a .zip file rather than an
installer.
2—Unpack it and move it to the desired location, such as a
directory under “C:\Program Files”.
3—Add the location <javadirectory>/bin (this is
probably something like C:\Program Files\Java\jdk-12.0.1\bin , depending upon
where you chose to put it) to the system Path variable. Access the Path variable in Windows 10
through: Settings -> System -> About -> System Info -> Advanced
System Settings , Environment Variables button.
4--To test that it is installed and that it can be seen correctly,
open a Windows command line window. This
can be done either through a Start menu item (Windows System -> Command
Prompt) or the use of the Search Box in the Task Bar (type “cmd” or “command
prompt” or something similar). At the
Command Prompt, type “java –version” to establish that is a JVM visible from
everywhere. Type “javac –version” to
establish that there are JDK tools visible from everywhere. (You can use this test to determine the level
of Java support installed on an unfamiliar system. Various Microsoft Windows systems you
encounter may have none, only a JVM or both a JVM and JDK installed.)
Installing Eclipse
Download the Eclipse installer at https://www.eclipse.org/ . Normally you install applications in the “C:\Program
Files” (or “C:\Program Files (x86)” for 32-bit applications) directory. Depending upon which Windows 10 release you
have and how permissions are set up on your machine, the installer may complain
about trying to install in “C:\Program Files”.
It will likely try and default to a directory under “C:\Users\<currentuser>”
which should work fine.
Installing JavaFX
JavaFX is intended to replace Swing as the standard GUI
library for Java SE (Standard Edition). Since
the JDK 11 release in 2018, JavaFX is part of the open-source OpenJDK, under
the OpenJFX project. Back in version 8,
it was part of the Oracle JDK download.
Now it is downloaded and installed separately.
The main site for JavaFX is here: https://openjfx.io/ . The download link on this page directs to https://gluonhq.com/products/javafx/
. Gluon is a development tools,
libraries and infrastructure company that would appear to be hosting the JavaFX
SDK, among other things. JavaFX can be
downloaded in two forms from this location: as a platform-specific SDK and as a
set of JMODs. JMODs can be used at
compile and link time, but not at run time.
(https://stackoverflow.com/questions/51843208/running-javafx-sample-on-jdk-11-with-openjfx-11-jmods-on-module-path) So download the SDK form. As to which version, it would be a debate
between the most recent version and the LTS (Long Term Support) version. While it seems that the Long Term Support may
only be available via contract, download that version anyway. The support fixes may end up being publicly
available. As of this writing, the public
LTS version is 11.0.2 . (By contrast,
the most current version is 12.0.2 .)
Instructions on what to do upon downloading are here: https://openjfx.io/openjfx-docs/ (the
Getting Started link on the openjfx.io page).
Jump to the “Run HelloWorld using JavaFX 12” section (from the column of
links on the left side). Unzip the
JavaFX SDK downloaded .zip file and copy the JavaFX sdk directory to an appropriate
permanent location if it is not already there.
Next to the Java SDK directory would make sense, such as “C:\Program
Files\Java\javafx-sdk-11.0.2” . On the
instructions web page, click on the Windows tab to get the Windows version of
the commands. The instructions would
suggest using the ‘set’ command at the Command Prompt to create the environment
variable “PATH_TO_FX” . The problem with
this method is that the newly created environment variable will only remain for
the duration of that particular command line session. For Windows, a more permanent way would be to
create the new variable in the same place that the PATH variable was updated,
namely Settings -> System -> About -> System Info -> Advanced
System Settings -> Environment Variables .
Use New… to create the System Variable, with PATH_TO_FX being the
Variable name and the directory path being the Variable value. (To show all of the current environment
variables at the Windows command prompt, use the ‘set’ command with no
parameters.)
Testing the FX installation:
There is a link to the HelloFX.java sample program from the above openjfx-docs page. This goes to a GitHub repository. We will skip over pulling it down with Git
until later, for now it is easy enough to copy the program off the web page and
paste it into a text browser. Save the
program as HelloFX.java to a working directory.
There is a command on the documentation page to compile:
javac --module-path
%PATH_TO_FX% --add-modules javafx.controls HelloFX.java
If you have the PATH_TO_FX variable something like
C:\Program Files\Java\javafx-sdk-11.0.2\lib , this command will result in an three
line error message:
error: invalid flag: Files\Java\javafx-sdk-11.0.2\lib
Usage: javac <options> <source files>
use --help for a list of possible options
This is because there is a space in the pathname. This can be rectified by adding quotes around
the part of the command that decomposes the PATH_TO_FX variable:
javac --module-path "%PATH_TO_FX%" --add-modules
javafx.controls HelloFX.java
This should create a class file in the working
directory. Run it using the java
command, again adding the quotes in the command:
java --module-path "%PATH_TO_FX%" --add-modules
javafx.controls HelloFX
This should pop up a new window on the screen with the text
“Hello, JavaFX 11.0.2, running on Java 12.0.1” in the middle (if all of the
installed versions are the same).
Friday, August 24, 2018
A Somewhat Disappointing Description of Bitcoin
The article "What Is the Blockchain?" appeared in the April 2018 issue of IEEE Computing Edge, authored by Massimo Di Pierro. It also originally appeared in the September/October 2017 issue of IEEE Computing in Science & Engineering.
I was somewhat surprised and disappointed that this article was published in its current form.
The section describing what a Bitcoin fundamentally is and how it is created is not correct. It is incorrect even when you allow for simplification in order to explain it to a reader without specific domain experience in this area.
The text of this section is as follows:
"A unit of bitcoin is nothing other than a number, but only some numbers are valid bitcoins. These numbers are solutions solutions of a well-defined equation, and whoever finds a new solution owns it (this process is called mining). Once a bitcoin is discovered, it can be traded, with transactions stored in a ledger. Transactions are digitally signed with the credentials of the seller to avoid nonrepudiation. There is no centralized ledger because users wouldn't trust one and because there are too many transactions to store them all in one place. Hence bitcoin and other cryptocurrencies provide a distributed ledger in which every computer involved in the transaction of a specific coin (or fraction of a coin) keeps a copy of the history of that coin's transactions. The blockchain technology makes sure that no party storing this history can tamper with it without being detected."
1) Each Bitcoin not assigned a number. And they are not created by finding one of these magic numbers. While this description does align with the term "mining" (which to me has never seemed like an accurate description of what was actually occurring), it is not correct.
a) "Mining" is actually a race to validate the next set of transactions, gathered in a block. The kicker here is that a successful "mining" operation, in addition to validating the transactions, also has to calculate a qualifying hash (using the hash function SHA256) of the block. The block header has fields built in that can be iterated upon in order to vary the hash result. The current race is won when a "miner" has successfully found a qualifying hash value. As more computing power is devoted worldwide to mining, the calculation difficulty of what counts as a "qualifying" hash is periodically adjusted (every 2016 blocks) so that rate at which new blocks are turned out remains at approximately once every 10 minutes. Bitcoins are created when the winner of the current block race assigns himself a number of Bitcoins through an additional transaction (called the coinbase transaction). This reward was originally 50 per block but is currently 12.5 and is cut in half every 210,000 blocks, which is approximately every four years. This is the established reward for doing the block validation work and winning the current validation race.
b) Bitcoins are not individually identified - they are only identified as quantities in transactions. Therefore, you can't actually trace a bitcoin in the system, only the transactions. This becomes even more evident when you pay attention to the fact that the smallest unit of currency the system will transact is not a bitcoin, but rather 1/100,000,000th of a bitcoin, which is known as a satoshi.
2) There is in fact a centralized ledger. Not centralized in that there is only one copy, but centralized in that all transactions in the system can be stored on a single node. Note that transactions are stored, not the Bitcoins themselves. A person (wallet id, actually) can create outgoing transactions to spend Bitcoins (or fractions thereof) by referencing incoming transactions. While not all nodes on the Bitcoin network maintain a full, up-to-date copy of the Bitcoin blockchain, many do. These are full nodes and they can autonomously and authoritatively verify any transaction without external reference. The size of the full blockchain can be found by conducting an internet search (ex. "bitcoin full blockchain size"). One site listing the historical size is: https://www.statista.com/statistics/647523/worldwide-bitcoin-blockchain-size/ . According to this site, "The size of the Bitcoin blockchain has been growing since the creation of the Bitcoin virtual currency in 2009, reaching approximately 173 gigabytes in size by the end of June 2018."
Additionally, not worth mentioning on its own but as long as we are here, there is a typo in the article author's first Python function code example. The function converts the parameters into a combined "token" object, but then does does not use that object in the hash function computation, instead using one of the function's input parameters.
For those wanting a whole book's worth of how Bitcoin works, I recommend the book "Mastering Bitcoin: Programming the Open Blockchain" by Andreas M. Antonopoulos.
I was somewhat surprised and disappointed that this article was published in its current form.
The section describing what a Bitcoin fundamentally is and how it is created is not correct. It is incorrect even when you allow for simplification in order to explain it to a reader without specific domain experience in this area.
The text of this section is as follows:
"A unit of bitcoin is nothing other than a number, but only some numbers are valid bitcoins. These numbers are solutions solutions of a well-defined equation, and whoever finds a new solution owns it (this process is called mining). Once a bitcoin is discovered, it can be traded, with transactions stored in a ledger. Transactions are digitally signed with the credentials of the seller to avoid nonrepudiation. There is no centralized ledger because users wouldn't trust one and because there are too many transactions to store them all in one place. Hence bitcoin and other cryptocurrencies provide a distributed ledger in which every computer involved in the transaction of a specific coin (or fraction of a coin) keeps a copy of the history of that coin's transactions. The blockchain technology makes sure that no party storing this history can tamper with it without being detected."
1) Each Bitcoin not assigned a number. And they are not created by finding one of these magic numbers. While this description does align with the term "mining" (which to me has never seemed like an accurate description of what was actually occurring), it is not correct.
a) "Mining" is actually a race to validate the next set of transactions, gathered in a block. The kicker here is that a successful "mining" operation, in addition to validating the transactions, also has to calculate a qualifying hash (using the hash function SHA256) of the block. The block header has fields built in that can be iterated upon in order to vary the hash result. The current race is won when a "miner" has successfully found a qualifying hash value. As more computing power is devoted worldwide to mining, the calculation difficulty of what counts as a "qualifying" hash is periodically adjusted (every 2016 blocks) so that rate at which new blocks are turned out remains at approximately once every 10 minutes. Bitcoins are created when the winner of the current block race assigns himself a number of Bitcoins through an additional transaction (called the coinbase transaction). This reward was originally 50 per block but is currently 12.5 and is cut in half every 210,000 blocks, which is approximately every four years. This is the established reward for doing the block validation work and winning the current validation race.
b) Bitcoins are not individually identified - they are only identified as quantities in transactions. Therefore, you can't actually trace a bitcoin in the system, only the transactions. This becomes even more evident when you pay attention to the fact that the smallest unit of currency the system will transact is not a bitcoin, but rather 1/100,000,000th of a bitcoin, which is known as a satoshi.
2) There is in fact a centralized ledger. Not centralized in that there is only one copy, but centralized in that all transactions in the system can be stored on a single node. Note that transactions are stored, not the Bitcoins themselves. A person (wallet id, actually) can create outgoing transactions to spend Bitcoins (or fractions thereof) by referencing incoming transactions. While not all nodes on the Bitcoin network maintain a full, up-to-date copy of the Bitcoin blockchain, many do. These are full nodes and they can autonomously and authoritatively verify any transaction without external reference. The size of the full blockchain can be found by conducting an internet search (ex. "bitcoin full blockchain size"). One site listing the historical size is: https://www.statista.com/statistics/647523/worldwide-bitcoin-blockchain-size/ . According to this site, "The size of the Bitcoin blockchain has been growing since the creation of the Bitcoin virtual currency in 2009, reaching approximately 173 gigabytes in size by the end of June 2018."
Additionally, not worth mentioning on its own but as long as we are here, there is a typo in the article author's first Python function code example. The function converts the parameters into a combined "token" object, but then does does not use that object in the hash function computation, instead using one of the function's input parameters.
For those wanting a whole book's worth of how Bitcoin works, I recommend the book "Mastering Bitcoin: Programming the Open Blockchain" by Andreas M. Antonopoulos.
Subscribe to:
Posts (Atom)