Accessing javaFX elements from Java Code (outside controller classes) - java

Is it possible to edit/access javaFX elements (such as Buttons, Labels, etc.) in java code which is NOT the controller class?
I have written an entire program in java and want to make a GUI for it in javaFX (using Scene Builder). Since the entire code ALREADY is written in Java classes outside the FXML-controller class, is it possible to access elements like "Labels" inside my already written classes?
All I want to do is use this code outside the FXML-controller class:
label1.setText("Something");
So it updates on the GUI.
If not, it is a very time-consuming process to implement my java code in the FXML-controller class.

So I think your solution depends on how safe you need your information to be when interfacing with the FX GUI. If you are OK providing your data directly to the controller, then I'd suggest simply passing your data object into the controller's constructor and storing a reference to it locally. You can then use any getters/setters from the data object to populate your GUI, or update the model.
public class Controller {
private Object dataObject;
public Controller(Object dataObject) {
this.dataObject = dataObject;
}
}
However, if you want to protect your data, and prevent the GUI from directly modifying or interacting with it - you'll need to use a wrapper that protects your information.
public class Wrapper {
private Object dataObject;
public Controller(Object dataObject) {
this.dataObject = dataObject;
}
// allowable function call
public Object functionOne() {
return dataObject.functionOne();
}
}
You only need to implement functions in the wrapper that are directly needed by the GUI, thus preventing calls into your data object that you think should be restricted from the GUI.
Your controller then becomes:
public class Controller {
private Wrapper dataObject;
public Controller(Wrapper dataObject) {
this.dataObject = dataObject;
}
}

Related

Identification of a service

Service interface:
public interface UserInterface {
void present();
void onStart();
void onStop();
}
I have two implementations: TextUserInterface and GraphicalUserInterface.
How can I identify the one I want to use when I launch my program? Source
private static void main(String[] args) {
ServiceLoader<UserInterface> uiLoader = ServiceLoader.load(UserInterface.class);
UserInterface ui = uiLoader.? //what to do to identify the one I want to use?
}
I was thinking of introducing an enum with the type of UI, so I could just iterate through all services and pick the one I'd like to, but isn't this approach just a misuse of services? In this case when I want to pick GraphicalUserInterface I could just skip the ServiceLoader part and just instantiate one. The only difference I see is fact that without services, I'd have to require the GraphicalUserInterface module, which "kind of" breaks the encapsulation.
I don't actually think that it would be a misuse of it. As a matter of fact, what you get from ServiceLoader.load(...) method is an Iteratable object, and if you need for a specific service, you will have to iterate through all the available instances.
The idea of the enum is not that bad, but I suggest that you take advantage of the Java stream and filter for the instance you need. For example, you might have something like that:
enum UserInterfaceType {
TEXT_UI, GRAPH_UI;
}
public interface UserInterface {
UserInterfaceType getTypeUI();
...
}
// In your main method
ServiceLoader<UserInterface> uiLoader = ServiceLoader.load(UserInterface.class);
UserInterface ui = uiLoader.steam()
.filter(p -> p->getTypeUI() == <TypeUIyouNeed> )
.findFirst()
.get();
That is open to a number of possibilities, for example you can put this is a separated method, which receives in input a UserInterfaceType value, and it can retrieve the service implementation based on the type enum value you passed.
As I said, that is just the main idea, but definitely you are not doing any misuse of the ServiceLoader.

RxJava: How to subscribe to the events of a different class

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
}
}

Pass a render function via property definition of custom control

I have built a custom control which renders an arraylist of java objects via a repeat control. Via the property definition I can provide which fields from the underlying java object I want to display. In the back-end I read this value e.g. via
obj[compositeData.columnField1]
This works well with static data, but sometimes I want to format the before rendering e.g. when the field contains a notesname and I only want to display the commonname.
I am wondering how I could set up something like that.
Now I am only passing the field name, which will be picked up by the cc to read the value.
E.g. for the jQuery DataTables plugin you can define a render function for a column and use the data variable of that column within that render function (e.g. build an anchor link or button in that column).
Can I provide something similar for SSJS e.g. I pass the render function as text (or object?) and in the back-end it will be transformed to ssjs.
Functions in JavaScript are first class citizens on objects. Presume you created a JS object with all the rendering functions and stored it in one of the scopes. E.g. viewScope.renderFunctions. Then hand over the name of the render function and inside use something like:
var renderfunc = viewScope.renderFunctions[funcname];
var result = renderfunc(rawdata);
return result;
That should do the trick
I found an answer here on stackoverflow. The eventhandler for my button looks as followed:
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{javascript:if (compositeData.actionButton.action) if (!compositeData.actionButton.action.call()) return;}">
</xp:eventHandler>
For my custom control I have set up a property:
<property>
<property-name>action</property-name>
<property-class>javax.faces.el.MethodBinding</property-class>
<property-extension>
<designer-extension>
<editor>com.ibm.workplace.designer.ide.xfaces.internal.editors.MethodBindingEditor</editor>
</designer-extension>
</property-extension>
<description>ssjs that action button must perform</description>
</property>
Make sure the class and editor are as above.
Then the property on the xpage containing the custom control contains the ssjs:
action="#{javascript:removeSelected}"
This is a function that resides in a SSJS script library. The key here is not to provide ANY parameters of parantheses (!!!)
The SSJS function is as followed:
function removeSelected(){
var accessList = sessionScope.get("removalList");
var nsf_committee = datasources["COM1_DB_FILEPATH"];
var db:NotesDatabase = session.getDatabase(session.getServerName(), nsf_committee);
for (var i = 0; i < accessList.length; i++) {
var doc:NotesDocument = db.getDocumentByUNID(accessList[i]);
if (null != doc){
doc.remove(true);
accessList.remove(accessList[i]);
}
}
}
(here I remove documents from the database. the unid id's reside in a an arraylist. the array list is set via a checkbox group for each row in my repeat control.)
Considering you would likely want to re-use the component in many contexts of your app I would approach the problem with an helper class and interface
public class FieldManager {
public static interface FieldDetail {
String getName();
void getAction();
}
private List<FieldDetail> fieldDetails = new List<FieldDetail>();
public FieldManager() {
}
public FieldManager(List<FieldDetail> fieldDetails) {
this.fieldDetails.addAll(fieldDetails);
}
public void addFieldDetail(FieldDetail fieldDetail) {
this.fieldDetails.add(fieldDetail);
}
public List<FieldDetail> getFieldDetails() {
return fieldDetails;
}
}
With this succinct definition you could now be able to implement the FieldDetail interface with a generic class or alternative specialized classes.
Then in the custom control you set a property as value or whatever, the <property-class> tag will be FieldManager and in the custom control you would know how everything plays out because the class FieldManager and the FieldDetail are the contract for you.
<xp:repeat disableOutputTag="true"
value="#{compositeData.value.fieldDetails}" var="fieldDetail">
<xp:link text="#{fieldDetail.name}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{fieldDetail.action}">
</xp:eventHandler>
</xp:link>
</xp:repeat>
Or whatever your code might be. Anyway, that's the gist of it.

Accessing static form from GUIbuilder via code

I am a total newbie with Codename One and have been studying up by watching the various tutorials etc. But there is a basic concept that I just can't seem to grasp.
When I design a form in the GUIBuilder, how do I reference the form from my code?
I.e. I designed my form in the UI Builder. Now in my main source code, I would like to add a toolbar to the form. Inside the GUIBuilder the form is called "Main", but statements such as Main.show(), Main.hide() etc do not work.
I managed to get the form "imported" for lack of a better word by using
private Form home;
...
...
home=Display.getInstance().getCurrent();
...
home.getToolbar().addCommandToOverflowMenu(edit);
Which works, but surely there must be a way of accessing the form directly without having to get the currently active instance? i.e. Something like
Main.getToolbar().addCommandToOverflowMenu(edit);
You can override the beforeShow() and postShow() of your form and just reference the parameter which represents the form.
To add commands, it's advisable that you do that in the beforeShow() method and long process like remote data fetching should be done in postShow().
For instance, let's say your form name is Main and was created in GUI Builder, you can do the following:
#Override
protected void beforeMain(final Form f) {
f.removeAllCommands();
Toolbar toolbar = new Toolbar();
f.setToolbar(toolbar);
toolbar.setTitleComponent(new Label("My Form Name", "Title"));
toolbar.addCommandToOverflowMenu(edit);
toolbar.addCommandToRightBar(backCommand);
f.setBackCommand(backCommand);
...
}
#Override
protected void postMain(final Form f) {
//fetch remote data here
...
}

How to model POJO from Vaadin UI? (Best practice)

I am working on a PDF Invoice generator in Vaadin 7. The code as it stands at the time of this writing can be found here. The repo includes a crude class diagram.
My question concerns the best practice of collecting the user input from the TextField and other Vaadin components to create an instance of Invoice.
Currently it works like this:
When the user clicks the button to generate the pdf, the class VaadinInvoiceGui (a Panel) calls the method createPdf(VaadinInvoiceGui gui) in the class VaadinInvoiceController.
VaadinInvoiceController calls method getInvoiceFromForm(VaadinInvoiceGui gui) in class InvoiceMapperImpl.
InvoiceMapperIml creates and returns an Invoice (POJO) by calling get methods in the VaadinInvoiceGui that gets passed to it. These getters return the values of the components in the view.
VaadinInvoiceController takes the Invoice returned by InvoiceMapperImpl and goes on to create pdf from it etc..
The getters in VaadinInvoiceGui look like this.
public String getCustomerName() {
return infoPanel.getCustomerNameTextField().getValue().toString();
}
public String getCustomerStreet() {
return infoPanel.getCustomerStreetTextField().getValue().toString();
}
public String getCustomerCity() {
return infoPanel.getCustomerCityTextField().getValue().toString();
}
...
I really don't feel like it's a good idea to pass the whole gui class to the controller and especially to the mapper, but I'm not sure what would be a better way of doing it. I could change the method createPdf(VaadinInvoiceGui gui) to something like createPdf(String customer name, String customerStreet, ...) but the number of parameters of the method would grow huge. I could do it using setters but then it would basically be doing the object mapping in the gui which doesn't seem like a very clean idea either.
What is the proper way of doing this?
Write a bean for the data to pass around as your model. Then use the FieldGroup to bind between model and form. Wrap the model as BeanItem<Model>. Binding is either done by name (convention) or by annotation #PropertyId.
master-detail-example: https://vaadin.com/wiki/-/wiki/Main/Creating+a+master-details+view+for+editing+persons
general infos: https://vaadin.com/book/vaadin7/-/page/datamodel.html
binding in forms: https://vaadin.com/book/vaadin7/-/page/datamodel.itembinding.html

Categories

Resources