Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Writing to a TextArea from a non-instantiating class

 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I've been struggling with this now for several days ... Googling, experimenting with code, reading books ... and I can't, for the life of me, seem to understand what I'm sure is a relatively simple thing to understand.

Lets make it simple ... let's say you have created a simple project with a FXML (yes, I'm trying to do this in JavaFX) form that has a button and a TextArea object on it. The Main class instantiates and creates the form. It also handles the button click event and it initially populates the TextArea with some text. Now, lets create two more classes that also need to APPEND text in that initially created TextArea.

Can someone show me some code that would actually accomplish this? Because the issue seems to be with referencing the initially created instance of Main, and being able to have those second and third classes access that instance of Main and thereby append text into that TextArea.

Thank you,

Mike Sims
 
Mohamed Sanaulla
Saloon Keeper
Posts: 3165
34
Google App Engine Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can you show us the code you have? Without which it would be very hard to help you out.
 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Mohamed Sanaulla wrote:Can you show us the code you have? Without which it would be very hard to help you out.


OK, I wrote something simple that will demonstrate my problem, although - all I really need to see, is some code that demonstrates how to instantiate a FXML form in one class, then use another class to update one of the controls from the instantiating class. I wanted to avoid specific code, so that I can see the basics of how it's done.

But since you asked, here is some code. I get this error when I run it and press the Process button:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException


Here is the Main class:



Here is the Controller class:



Here is the DoWork class



And here is the ProcessData class

 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Moderator, I marked this topic as resolved on accident ... but I can't see anywhere to un-mark it as resolved.
 
Campbell Ritchie
Sheriff
Posts: 51419
87
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
… but I can mark it unresolved. Thereygo, as they say round here.
 
John Damien Smith
Ranch Hand
Posts: 299
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
> all I really need to see, is some code that demonstrates how to instantiate a FXML form in one class, then use another class to update one of the controls from the instantiating class.

Review this StackOverflow question and see if it helps:
http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml
 
John Damien Smith
Ranch Hand
Posts: 299
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are using the wrong import statement:

import java.awt.*;

You should never import awt/swing classes into a pure JavaFX project.

The wrong import is causing the reflection exception, because the FXMLLoader is expecting your code to have a javafx.event.ActionEvent, not an java.awt.ActionEvent, so it can't find and invoke an appropriate method to handle the event.

You should not have a static reference on an @FXML variable: that won't work in later JavaFX versions (and is a bad idea anyway):
http://stackoverflow.com/questions/23105433/javafx-8-compatibility-issues-fxml-static-fields
Using static anything in a program for anything which is not an immutable constant is usually a not a very good idea if you can avoid it.

You do not want to write new Controller() as the FXMLLoader will create controllers for you.

There may be (probably are) other issues in your code or design, I haven't spent any time to check.
 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Damien Smith wrote:> all I really need to see, is some code that demonstrates how to instantiate a FXML form in one class, then use another class to update one of the controls from the instantiating class.

Review this StackOverflow question and see if it helps:
http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml


Oh my YES! This is the first thing I’ve read in all the time I’ve spent on this that actually bridges the gap between the instantiating class and other classes. I read the second link you provided as well. Now, I’m going to play with the sample code I posted and see if I can’t get something resembling a decent and concise structure that actually functions.

Thank you, I will update this topic soon.

Michael
 
John Damien Smith
Ranch Hand
Posts: 299
14
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Cool, glad that helped. Other resources which might be useful to you are:
http://stackoverflow.com/questions/27071068/javafx-pass-value-to-another-cass-and-update-label-text (non-fxml based model instance sharing example)
https://community.oracle.com/message/12754784 (discussion on adapting the previous example to fxml)
 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Isn’t there a way in Java, to create an instance of a class, and then have that instance’s public methods, procedures and properties GLOBALLY accessible to every class in the program throughout the life of the program (while it’s running)? Conceptually, this seems like a very simple thing to me, and it would absolutely model real life (i.e. a baby is born, the human class was instantiated... and every existing or future class of human can absolutely access the new human instance).
 
John Damien Smith
Ranch Hand
Posts: 299
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
> Isn’t there a way in Java, to create an instance of a class, and then have that instance’s public methods, procedures and properties GLOBALLY accessible to every class in the program throughout the life of the program (while it’s running)?

Yes, you can use a singleton pattern, though some consider it an anti-pattern.

You can use a dependency injection framework (such as afterburner.fx) to achieve something like a global view into system components (or rather the parts of the global view required by components is injected into them by the framework).

There are other mechanisms for loosely coupling components, for example
- the observer pattern that the JavaFX property system is based on
- an event bus.
 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Damien Smith wrote:>Yes, you can use a singleton pattern, though some consider it an anti-pattern.

You can use a dependency injection framework (such as afterburner.fx) to achieve something like a global view into system components (or rather the parts of the global view required by components is injected into them by the framework).

There are other mechanisms for loosely coupling components, for example
- the observer pattern that the JavaFX property system is based on
- an event bus.

I was hoping that there was simply a way to set something in the Main class which told Java simply, "Make all instantiated classes available to all other classes" perhaps using a class instance ID or something ... But absent something that simple, this is how I ultimately ended up doing it...

I have my app centered on the JavaFX controller class, which is basically a 'branching cop'. If anything happens in the app, it starts with the controller. Then, in every other class, I create a method such that the controller can pass itself into the class so that the class can refer back to that instance of the controller and thereby get to any other instantiated classes through the controller. Here is a generic example I whipped up showing generally how I do it, using an example of code that is intended to allow a user to process data:









Notice in method specialCases, I can get the log path from the controller class which ultimately received that path from the FileActions class when it was instantiated. Of course, I could have instantiated the FileActions class directly within the DataFormatting class and received the exact same path, but in my case, it was imperative that I kept only one instantiation of each class because I have a much more complex network of variables which are necessary to read and change from different classes ensuring that when one class changes a variable, a completely different class is then able to get from that variable, whatever a certain class did to it, and if each class had separate instantiations of the other classes, then a third classes modification to a relevant variable would not be visible to whatever class was relevant at that point in time.

I'm not sure what you would label my specific way of keeping class instances available to every other class in the project, but I guess you could say that I implemented Java's 'getter / setter' train of thought and implemented it at the class level, using one class (the controller) as the parent class for all other classes.

Mike
 
John Damien Smith
Ranch Hand
Posts: 299
14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for posting your solution Michael. Glad you have something which works for you.

Your idea to centralize the navigation control is similar to one that I had when I created this small framework for navigation of FXML based scenes.
Your solution uses object passing whereas mine uses static data, but the overall effect seems similar.
A more extensive solution is that presented by Angela Caicedo for multiple scene navigation in JavaFX.

I still think that the dependency injection based approach I mentioned earlier such as Afterburner is cleaner than the either the object passing or static data approach, but I understand that concepts like dependency injection can sometimes seem strange to people.

The following is going to get a bit dense and may be difficult to understand. It's just advice, so if it confuses more than it helps, please ignore it for now and you always come back and study things like this later.

Some advice on your implementation is to concentrate a little more on design, try to stick to the Single Responsibility Priniciple (that is why I have a separate Navigator class to manage navigation rather than overloading the Application class to perform navigation tasks).

Try not to do things which add additional, potentially unnecessary framework boilerplate code to all your classes - e.g. SceneBuilder has a function where it generates a template controller class from a FXML class, if you write your app such that you basically stick to that template and just add some more additions for the functionality you require then it makes switching between the graphical design tool and your app code easier.

Be careful with your approach of having a lot of globally accessible state in your application (for the reasons mentioned in the linked article).

Your approach limits you to just a single Controller class for the system, whereas it might be best to segregate different controllers for different parts of the system where each controller is just encapsulating the UI elements for a smaller part of the whole system.

What you can have is a kind of model (or view-model in an MVVM architecture nomenclature) based system, potentially based on the property binding and listeners where the model or view-model knows nothing of the associated GUI components but instead provides listeners. The controller classes are set with the view-model references either passed in to them via constructors or methods or via dependency injection. This provides a separation of concerns whereby the controllers do the binding of the model to the UI and the models themselves react to changes via property listeners, potentially calling into functions on domain objects which take actions based upon the data (for example your file actions). An example of a listener driven approach for providing a skinnable application is this tic-tac-toe game. The way I described things in this paragraph is pretty much the same as the internal JavaFX control architecture and is what gives the controls a lot of their flexibility to separate behavior styling and functionality, such that you can completely re-skin a control (e.g. a ComboBox can have a traditional mouse driven drop down control on a desktop or a rolodex style touch driven control on a mobile interface) but the API to use the control never changes.

The disadvantage of the indirect property change listener approach to programming is that it can make some things more difficult to understand as a lot of operations are driven by listeners invoked as side-effects of data changing (so it's a tradeoff between using the abstract model approach or just embedding all the logic and data you need into the controller). So the lead developer for JavaFX controls doesn't advise that users write controls for all elements of their application - only those which need compartmentalization or are good candidates for standardizing in a library. Nevertheless it is good to really understand these kind of concepts so that you can make good decisions on when to apply them as you can still make use of some of the concepts for the controls development without actually inheriting from the Control class.

One great thing about using concepts like the single responsibility principle and separation of concerns is that it makes your application much easier to test. When you have a lot of shared state and mixed responsibilities it is very difficult to unit test functionality in isolation.

The event driven concepts for property change events also set your application up reactive programming model which is the basis for libraries such as ReactFX (although I would still tend treat reactive programming with JavaFX as a bit more of an experimental thing for now rather than something your would generally use in production code).
 
Michael D Sims
Ranch Hand
Posts: 70
1
Chrome Java Mac
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
John Damien Smith wrote:I still think that the dependency injection based approach I mentioned earlier such as Afterburner is cleaner than the either the object passing or static data approach, but I understand that concepts like dependency injection can sometimes seem strange to people.

I watched most of the first video on the link you posted, and I THINK I felt like I knew what was kinda going on ... but he went so damn fast, I couldn't follow him. Also, I still have no idea what Afterburner actually DOES or why someone would use it (which is, of course, THE VERY THING you're trying to help me understand - and I get that completely).
John Damien Smith wrote:The following is going to get a bit dense and may be difficult to understand.

OK, so I read through what you wrote one time so far. From behind my eyeballs, what you wrote was very dense with information, concepts, principles and just a lot of nomenclature that I, frankly, haven't the first clue about in terms of understanding. Which makes reading it a tad challenging... Which only makes me want to dig in and learn it so that I can understand it.

Thank you for taking the time to compose these posts for me. You have no idea how much I appreciate it. And if you are available as I progress in this, I'd love to hit you up with questions etc.

Michael
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic