Java FX properties is a nice API allowing the developer to create properties instead of using standard get/set method semantics. It also adds subscription to changes, properties expressions support for basic types and collections. Though properties are there in C# as a part of the language, these properties are available only inside the JavaFX container. I.e. if you try listening to changes, you'll run into an IllegalStateException saying that you need to run your listener code inside the main JavaFX thread.
So is there an alternative available for the rest of the Java world?
Update
Here is an example of an IllegalStateException. Am I misusing JavaFX API?
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("s1");
list.add("s2");
ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener<String>() {
#Override
public void onChanged(Change<? extends String> change) {
System.out.println("added: " + change.getAddedSubList());
}
});
observableList.add("s3");
}
}
Exception:
Exception in thread "main" java.lang.IllegalStateException
at com.sun.javafx.collections.NonIterableChange.checkState(NonIterableChange.java:101)
at com.sun.javafx.collections.NonIterableChange.getPermutation(NonIterableChange.java:81)
at javafx.collections.ListChangeListener$Change.wasPermutated(ListChangeListener.java:156)
at javafx.collections.ListChangeListener$Change.getAddedSubList(ListChangeListener.java:212)
at Test$1.onChanged(Test.java:23)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:134)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:48)
at com.sun.javafx.collections.ObservableListWrapper.callObservers(ObservableListWrapper.java:97)
at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:154)
at com.sun.javafx.collections.ObservableListWrapper.add(ObservableListWrapper.java:144)
at Test.main(Test.java:27)
Answer
JavaFX properties can be used independently to the rest of the JavaFX system and there is no requirement that properties on objects that do not effect an active JavaFX Scene Graph have their listener code run on the JavaFX application thread.
Explanation
Running listener code on the JavaFX application thread is only required when the change listeners or bindings effect properties of Nodes in a Scene Graph:
An application must attach nodes to a Scene, and modify nodes that are already attached to a Scene, on the JavaFX Application Thread.
You can write Java programs that use JavaFX properties and have no nodes or scene graph. You can supply properties and change listeners executable on non-JavaFX threads for objects which have no interaction with the scene graph.
Sample
The Oracle JavaFX properties and binding tutorial demonstrates use of JavaFX properties in programs which use no other JavaFX components and have no JavaFX application thread.
Additional sample based on questions in comments
Thanks, examples in this tutorial work for me. However I tried listening to the ObservableList collection and got this exception. Am I doing something wrong?
You are doing something wrong.
I tried running the sample code you added to your question on Java 8, and the error message is more explicit:
Exception in thread "main" java.lang.IllegalStateException: Invalid Change state: next() must be called before inspecting the Change.
When you add a change.next() call, your test application functions as you would expect.
The javadoc for change.next() reads:
Go to the next change. In initial state is invalid a require a call to next() before calling other methods. The first next() call will make this object represent the first change.
Working sample code:
import javafx.collections.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("s1");
list.add("s2");
ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener<String>() {
#Override
public void onChanged(Change<? extends String> change) {
while (change.next()) {
System.out.println("added: " + change.getAddedSubList());
}
}
});
observableList.add("s3");
}
}
Output of sample code:
added: [s3]
Related
I am new to Spring Boot and just implemented a normal Spring Boot application with HTTP where endpoints receive data and put in a database. Now I want some data to put in both databases and a class with data structure. Since there will be continuous operations with this data I need to operate with it as a separate process.
#Service
public class RulesManager {
private HashMap<Integer, Rule> rules = new HashMap<Integer, Rule>();
public void addRule(Rule rule) {
// Add rule to the database
}
// should be running in the background
public void updateRules(){
// Continuous check of rules and update of this.rules HashMap
}
}
#SpringBootApplication
public class RulesApplication {
public static void main(String... args) {
SpringApplication.run(RulesApplication.class, args);
// How do I call RulesManager.updateRules() to run in the background and make changes to rules hashmap???
}
}
So while listening to HTTP requests I want my application to run background process which will never stop and repeat itself. I am not sure how to call that class from the main RulesApplication class so that both http requests and background process were able to make changes to this.rules HashMap. Will be grateful for any tip or advice.
If you are just looking to start a always on process when app starts ( even better when RuleManager gets initialized ), then you should simply create a new thread in the constructor of RuleManager :
methodCalledByConstructor()
{
new Thread(()->{
// loop start
// access and check the hashmap
// do what is necessary
// sleep for a sometime
// loop end
}).start();
}
But if the work is only required when some event occurs, then use observer pattern for more elegant solution.
Try to define a new Thread for example "LocalRulesHandling" and annotate it with #Component and inside this thread add your implementations regarding the rules hashmap.
In the RulesApplication class try to get the spring context and the get the execution thread bean and then start this thread.
ApplicationContext conttext = SpringApplication.run(RulesApplication.class, args);
LocalRulesHandling handling = context.getBean(LocalRulesHandling.class);
handling.start();
I have a question about how to conceptually create an Observer and link it to another class: I currently have a class called Simulation that is supposed to create TransactionCreated objects and publish them as events. Another class called TransactionReceiver is supposed to be an Observer of every event that is published by the Simulation class and work with them.
The main method is included in the Simulation class and starts by creating an event in a static context and publishing it which works. My question would be how I am supposed to connect the TransactionReceiver as an Observer and let it subscribe to those events by receiving them in a method and work with those received objects? Do I need to create another class that would include the main method and create a Simulation and TransactionReceiver object that are then linked together as Observable and Observer? How would that look like?
And if I would extend that system with several different classes would they all have to be linked together through one class that connects Observers and Observables?
Your app should only have one main method.
Conceptually, this should be where you do the initial setup of Simulation and TransactionReceiver, so perhaps you could move it to a separate class to help you visualise how things should work. You could try something like below:
class Application {
private Simulation simulation;
private TransactionReceiver transactionReceiver;
public Application() {
simulation = new Simulation(/* params here*/);
transactionReceiver = new TransactionReceiver(/*params here*/);
}
public void go() {
simulation.simulate().subscribe(transactionCreated -> transactionReceiver.doSomething(transactionCreated);
}
public static final main(String[] args) {
Application application = new Application();
application.go();
}
}
Eventually as you get more fluent you could think about adding a dependency-injection framework like Guice or Dagger.
This will help you with managing the dependencies of the classes that you need to use throughout your application.
So you would end up with a more simple Application - it would just set up the DI-framework and then you can use the classes how you want to.
UPDATE:
If you want to communicate between two different classes, you will need to use methods:
class Simulation {
public Observable<TransactionCreated> simulate() {
// use PublishSubject or whatever
}
}
I looked at the stackoverflow questiions that seem similar to my problem, but none were of any help.
Here is my problem:
For a project, I am making a JavaFX app that is in pure Java without FXML. I have two classes, a controller Controller class and a class containing gui stuff GUI.
Controller has a member variable of type GUI and I am trying to assign an event handler to one of the buttons in GUI but it doesn't seem to work. It only works when I try implementing the handler inside the GUI class, but I need it to work in Comtroller.
In the constructor of Controller is as follows:
this.view = view;
view.addSimpleHandler(new SimpleHandler());
view is of type GUI and addSimpleHandler is a member function of view
SimpleHandler is an inner class of Controller that implements EventHandler and overrides the handle() function
public void addSimpleHandler(EventHandler<ActionEvent> e) {
simpleButton.setOnAction(e);
}
here is my main method and class signature for GUI
public class GUI extends Application {
//member variables for the GUI design including simpleButton
private Button simpleButton;
public static void main(String[] args) {
GUI view = new GUI();
Controller controller = new Controller(view);
Application.launch(view.getClass(), args);
}
public GUI() {
simpleButton = new Button("Simple button");
//rest of code is setting up GUI into my panes
}
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(mainPane, sceneWidth, sceneHeight);
//mainPane is a pane that contains simpleButton with a screenwidth and screenHeight
primaryStage.setTitle("Simple");
primaryStage.setScene(scene);
primaryStage.show();
}
Don't instantiate your application class manually. To understand why, see the documentation regarding the JavaFX life-cycle (emphasis mine):
The entry point for JavaFX applications is the Application class. The JavaFX runtime does the following, in order, whenever an application is launched:
Starts the JavaFX runtime, if not already started (see Platform.startup(Runnable) for more information)
Constructs an instance of the specified Application class
Calls the init() method
Calls the start(javafx.stage.Stage) method
Waits for the application to finish, which happens when either of the following occur:
the application calls Platform.exit()
the last window has been closed and the implicitExit attribute on Platform is true
Calls the stop() method
As you can see, JavaFX itself will instantiate the application class and it's that instance which has its life-cycle methods invoked—those methods being init(), start(Stage), and stop(). However, in your code you have the following:
public static void main(String[] args) {
GUI view = new GUI(); // created your own instance
Controller controller = new Controller(view); // gave controller that instance
// Launches JavaFX which starts the life-cycle documented above
Application.launch(view.getClass(), args);
}
You create your own instance of GUI. This instance is not managed by JavaFX which means its start(Stage) method is never invoked. When you create the Controller instance and pass it your instance of GUI you're adding the EventHandler to a node which is never displayed. The window you see displayed is from the GUI instance created as part of the call to Application#launch and that GUI instance is never associated with a Controller.
For JavaFX applications you should consider the init() and start(Stage) methods as the entry points1. In other words, create the Controller in one of those aforementioned life-cycle methods. Although I suppose you could do the same in the constructor instead2. Whichever you choose, take note of which thread invoke each method, which is documented in the same place as the life-cycle. Here are the essentials:
The application class is loaded, initialized, and constructed on the JavaFX Application Thread.
The init() method is invoked by the JavaFX-Launcher thread.
The start(Stage) and stop() methods are invoked by the JavaFX Application Thread.
Remember that certain actions can only be executed on the JavaFX Application Thread.
1. You can still execute code before the call to Application#launch within the main method if needed. The only constraint is that code should not be directly related to JavaFX.
2. Your constructor is currently public and has zero parameters—keep it that way. JavaFX requires the application class to have a public, no-argument constructor in order to construct an instance via reflection.
I am somewhat new to the OSGi world. And some concepts still elude me.
I'm trying to create a graphical OSGi application using Swing, Equinox and Declarative Services. The goal is to ease the creation of plugins and extensions for the application.
I have stumbled with a design problem and, since I am doing this from the ground up, I want to use all the best practices I can.
I do have a bundle that contains the API and only exposes interfaces to be implemented as services.
public class SomeClass {
}
public interface Manager<T> {
void add(T obj);
void update(T obj);
void remove(T obj);
}
public interface SomeClassManager extends Manager<SomeClass> {
}
public interface Listener<T> {
void added(T obj);
void updated(T obj);
void removed(T obj);
}
public interface SomeClassListener extends Listener<SomeClass> {
}
Let's say I have a bundle (Core) that provides a service that is a manager of certain types of objects (It basically contains an internal List and adds, removes and updates it).
public class SomeClassCoreManager implements SomeClassManager {
private ArrayList<SomeClass> list = new ArrayList<SomeClass>();
private ArrayList<SomeListener> listeners = new ArrayList<SomeListener>();
protected void bindListener(SomeListener listener) {
listeners.add(listener);
}
protected void undindListener(SomeListener listener) {
listeners.remove(listener);
}
public void add(SomeClass obj) {
// Adds the object to the list
// Fires all the listeners with "added(obj)"
}
public void update(SomeClass obj) {
// Updates the object in the list.
// Fires all the listeners with "updated(obj)"
}
public void remove(SomeClass obj) {
// Removes the object from the list.
// Fires all the listeners with "removed(obj)"
}
}
I also have a second bundle (UI) that takes care of the main UI. It should not "care" for the object managing itself, but should be notified when an object is added, removed or changed in order to update a JTree. For that purpose I used a Whiteboard pattern: The UI bundle implements a service that is used by the Core bundle to fire object change events.
public class MainWindow extends JFrame {
private JTree tree = new JTree();
private SomeClassManager manager;
protected void activate() {
// Adds the tree and sets its model and creates the rest of the UI.
}
protected void bindManager(SomeClassManager manager) {
this.manager = manager;
}
protected unbindManager(SomeClassManager manager) {
this.manager = null;
}
}
public class SomeClassUIListener implements SomeClassListener {
public void added(SomeClass obj) {
// Should add the object to the JTree.
}
public void updated(SomeClass obj) {
// Should update the existing object in the JTree.
}
public void removed(SomeClass obj) {
// Should remove the existing object from the JTree.
}
}
My problem here is the following:
The MainWindow is a DS component. I am using its activator to initiate the whole UI. The instance creation is handled by OSGi.
In order to get the updates from the manager, I am exposing the SomeClassUIListener as a Declarative Service. Its instance is also handled by OSGi.
How should I access the instance of the JTree model from the SomeClassUIListener?
I have come up with several options but I am not sure which to use:
Option 1:
Use some kind of internal DI system for the UI bundle (like Guice or Pico) and put it in a class with a static method to get it and use it all over the bundle.
This approach seems to be frowned upon by some.
Option 2:
Inject a reference to the MainWindow (by turning it into a service) in the SomeClassUIListener through OSGi and go from there. Is this possible or advisable? Seems to me that it is the simpler solution. But, on the other hand, wouldn't this clutter the bundle with component config files as the UI got more and more complex?
Option 3:
Create a separate bundle only for listeners and use OSGi to update the MainWindow. This seems to me a bit extreme, as I would have to create an enormous amount of bundles as the UI complexity grows.
Option 4:
Use the MainWindow class to implement the Listener. But, the more services in the main UI bundle, the bigger the MainWindow class would be. I think this would not be a good option.
I cannot think of more options. Is any of the above the way to go? Or is there another option?
Thank you in advance.
Edit:
Just to clarify as Peter Kriens had some doubts about this question.
My goal here is to decouple the user interface from the Manager. By Manager I mean a kind of repository in which I store a certain type of objects (For instance, if you consider the Oracle's JTree tutorial at http://docs.oracle.com/javase/tutorial/uiswing/components/tree.html, the manager would contain instances of Books).
The Manager may be used by any other bundle but, according to my current plan, it would notify any listener registered in it. The listener may be the main UI bundle but may also be any other bundle that chooses to listen for updates.
I am not sure I completely grasp your proposal, and it feels like you are on your way to create a whole load of infrastructure. In OSGi this is generally not necessary, so why not start small and simple.
Your basic model is a manager and an extension. This is the domain model and I would try to flow things around here:
#Component(immediate)
public class ManagerImpl { // No API == immediate
List<Extension> extensions = new CopyOnWriteArrayList<Extension>();
JFrame frame = new JFrame();
#Reference(cardinality=MULTIPLE)
void addExtension( Extension e ) {
addComponent(frame, e.getName(), e.getComponent());
extensions.add(e);
}
void removeExtension( Extension e) {
if ( extensions.remove(e) ) {
removeComponent(frame, e.getName());
}
}
#Component
public class MyFirstExtension implements Extension {
public String getName() { return "My First Extension";}
public Component getComponent() { return new MyFirstExtensionComponent(this); }
}
Isn't this what you're looking for? Be very careful not to create all kinds of listeners, in general you find the events already in the OSGi registry.
Some option here would be to pass the tree model instance as the argument in the listeners methods.
public void added(JTree tree, SomeClass obj)
This way listeners manager would be responsible only for listeners logic, not for the tree state.
Another nice option would be to create a separated TreeProviderService, responsible for holding and serving singleton JTree instance for the application. In such case you would consume TreeProviderService directly from the listeners.
I propose to simply also use DS for the UI creation and wiring. If you use the annotations Peter mentioned you will not clutter your bundles with component descriptors in XML form.
So your listener is a #Component and you inject the UI elements it needs to update into it.
Btw. what you plan to do sounds a bit like databinding to me so you should also investigate what these offer already.
See: Swing data binding frameworks
Btw. you may also want to look for more advanced frameworks than swing. For example some time ago I did a small tutorial for vaadin: https://github.com/cschneider/Karaf-Tutorial/tree/master/vaadin
It already has a databinding for java beans. So this made it really easy for me to code the UI. The full UI is just this little class: https://github.com/cschneider/Karaf-Tutorial/blob/master/vaadin/tasklist-ui-vaadin/src/main/java/net/lr/tutorial/karaf/vaadin/ExampleApplication.java
In the old version I still needed a bridge to run vaadin in OSGi but version 7 should be quite OSGi ready.
In JavaFX, I have a Controller class that pulls control components from an FXML file and has methods that act on the component, shown with a Label here:
public class ViewController {
#FXML private Label labelStatus;
public void updateStatusLabel(String label) {
labelStatus.setText("Status: " + label);
}
}
I also have a Java Thread with a run() method, like this:
public class Server extends Thread {
public void run() {
super.run();
}
}
This Server thread handles some socket connections that I need for my particular application. After a connection has been established (in the run() method -- not shown), I need to update the Label in the FXML Controller. How would I do this?
Note: I've purposely made my code and question general so it may help others with the same problem.
You call Platform.runLater(runnable) off the JavaFX UI thread to execute a runnable that updates elements of the active JavaFX Scene Graph on the JavaFX UI thread.
Also review Concurrency in JavaFX, with the Task and Service classes and see if that is not a more appropriate solution to your particular task.
For more information, see:
Usage of JavaFX Platform.runLater and access to UI from a different thread.
Platform.runLater and Task in JavaFX
JavaFx response to SwingUtilities.invokeLater