Home » Eclipse Projects » e(fx)clipse » [Best Practices] UI Strucure & Events
[Best Practices] UI Strucure & Events [message #1096371] |
Wed, 28 August 2013 09:43 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Sorry for spamming the forum, but since I almost start from zero (again), I'm not sure about the best practices when it comes to JavaFX.
Currently I follow the following approach (not the best thing, I guess):
my_package.ui.Main - primary stage
my_package.ui.RootWindowCreator - the name is speaking
my_package.ui.DeviceWindowCreator - a "sub"-page
my_package.ui.res.bundle - translations
my_package.ui.res.layout - fxgraph & fxml files
Main.java (simplified)
ResourceBundle bundle = ResourceBundle.getBundle("my_package.ui.res.bundle.strings", Locale.getDefault());
RootWindowCreator rootWindow = new RootWindowCreator(primaryStage, bundle);
Scene scene = new Scene(rootWindow.getRootWindow(), DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
RootWindowCreator.java
public class RootWindowCreator {
private final Stage stage;
private final BorderPane rootWindow;
private final ResourceBundle bundle;
public Stage getStage() {
return stage;
}
public BorderPane getRootWindow() {
return rootWindow;
}
public ResourceBundle getBundle() {
return bundle;
}
public RootWindowCreator(Stage stage, ResourceBundle bundle) throws IOException {
this.stage = stage;
this.bundle = bundle;
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setResources(bundle);
this.rootWindow = (BorderPane) fxmlLoader.load(this.getClass().getResource("res/layout/Root.fxml").openStream());
if (fxmlLoader.getController() instanceof RootController) {
((RootController) fxmlLoader.getController()).setStage(stage);
}
fillNavigation();
}
private void fillNavigation() throws IOException {
outer: for (Node node : rootWindow.getChildren()) {
if (!node.getId().equals("splitPaneBody"))
continue;
for (Node childNode : ((SplitPane) node).getItems()) {
if (!childNode.getId().equals("accordionNavigation"))
continue;
Accordion navigation = (Accordion) childNode;
DevicesWindowCreator devicesWindow = new DevicesWindowCreator(stage, bundle);
navigation.getPanes().add(devicesWindow.getPane());
navigation.setExpandedPane(devicesWindow.getPane());
break outer;
}
break;
}
}
DeviceWindowCreator.java
Alsmost the same as the the RootWindowCreator.java, but without the Navigation thingy.
And of course there are the *Controller classes. But there is my problem. When I want to trigger an Event, that needs to be consumed by a complete other part of the UI, I have no idea of how to achive this in a clean way.
My best idea would be a central Event Handler. Is there something like this in JavaFX already? Otherwise I would implement it by my self. But it would be a bit ugly, since I would need to hook it to the Controller classes (or implement an internal Event Listener class there and register it on the central Event Handler).
For example: The device window would contain a method to trigger the discovery of the devices and should trigger an Event, that a) shows a progress bar on the root window (it is already there but set to be invisible) and a cancel button. Obviously the windows don't really know each other and there is no such method as #findViewById(String) as Android has - knowing the ID I could try to find the progress bar on the primary stage, that is part of the window creator classes, but not the controller...
I don't simply know, if this is a "good" approach. I want to try have a program with code as clean as possible and without ugly hacks, if there already is a standardized mean of doing something like this.
Thanks four your input and greetings,
Daniel
|
|
|
Re: [Best Practices] UI Strucure & Events [message #1096540 is a reply to message #1096371] |
Wed, 28 August 2013 14:32 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
I would use an event-bus which apparently is already there for you
because you can use the EventAdmin service from OSGi. You can also make
use of the IEventBroker by adding org.eclipse.e4.ui.services to your
application.
If you are using Eclipse DI you can also make use of the @EventTopic stuff.
Tom
On 28.08.13 11:43, Daniel Zimmermann wrote:
> Sorry for spamming the forum, but since I almost start from zero
> (again), I'm not sure about the best practices when it comes to JavaFX.
>
> Currently I follow the following approach (not the best thing, I guess):
>
> my_package.ui.Main - primary stage
> my_package.ui.RootWindowCreator - the name is speaking
> my_package.ui.DeviceWindowCreator - a "sub"-page
>
> my_package.ui.res.bundle - translations
> my_package.ui.res.layout - fxgraph & fxml files
>
> Main.java (simplified)
>
> ResourceBundle bundle =
> ResourceBundle.getBundle("my_package.ui.res.bundle.strings",
> Locale.getDefault());
> RootWindowCreator rootWindow = new RootWindowCreator(primaryStage, bundle);
> Scene scene = new Scene(rootWindow.getRootWindow(),
> DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
> primaryStage.setScene(scene);
> primaryStage.show();
>
>
> RootWindowCreator.java
>
> public class RootWindowCreator {
>
> private final Stage stage;
> private final BorderPane rootWindow;
>
> private final ResourceBundle bundle;
>
> public Stage getStage() {
> return stage;
> }
>
> public BorderPane getRootWindow() {
> return rootWindow;
> }
>
> public ResourceBundle getBundle() {
> return bundle;
> }
>
> public RootWindowCreator(Stage stage, ResourceBundle bundle) throws
> IOException {
> this.stage = stage;
> this.bundle = bundle;
> FXMLLoader fxmlLoader = new FXMLLoader();
> fxmlLoader.setResources(bundle);
> this.rootWindow = (BorderPane)
> fxmlLoader.load(this.getClass().getResource("res/layout/Root.fxml").openStream());
>
> if (fxmlLoader.getController() instanceof RootController) {
> ((RootController) fxmlLoader.getController()).setStage(stage);
> }
> fillNavigation();
> }
>
> private void fillNavigation() throws IOException {
>
> outer: for (Node node : rootWindow.getChildren()) {
> if (!node.getId().equals("splitPaneBody"))
> continue;
> for (Node childNode : ((SplitPane) node).getItems()) {
> if (!childNode.getId().equals("accordionNavigation"))
> continue;
> Accordion navigation = (Accordion) childNode;
> DevicesWindowCreator devicesWindow = new
> DevicesWindowCreator(stage, bundle);
> navigation.getPanes().add(devicesWindow.getPane());
> navigation.setExpandedPane(devicesWindow.getPane());
> break outer;
> }
> break;
> }
> }
>
>
> DeviceWindowCreator.java
>
> Alsmost the same as the the RootWindowCreator.java, but without the
> Navigation thingy.
>
>
> And of course there are the *Controller classes. But there is my
> problem. When I want to trigger an Event, that needs to be consumed by a
> complete other part of the UI, I have no idea of how to achive this in a
> clean way.
> My best idea would be a central Event Handler. Is there something like
> this in JavaFX already? Otherwise I would implement it by my self. But
> it would be a bit ugly, since I would need to hook it to the Controller
> classes (or implement an internal Event Listener class there and
> register it on the central Event Handler).
>
> For example: The device window would contain a method to trigger the
> discovery of the devices and should trigger an Event, that a) shows a
> progress bar on the root window (it is already there but set to be
> invisible) and a cancel button. Obviously the windows don't really know
> each other and there is no such method as #findViewById(String) as
> Android has - knowing the ID I could try to find the progress bar on the
> primary stage, that is part of the window creator classes, but not the
> controller...
>
> I don't simply know, if this is a "good" approach. I want to try have a
> program with code as clean as possible and without ugly hacks, if there
> already is a standardized mean of doing something like this.
>
> Thanks four your input and greetings,
> Daniel
|
|
| | | | | | | |
Re: [Best Practices] UI Strucure & Events [message #1097808 is a reply to message #1097401] |
Fri, 30 August 2013 07:22 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Funny enough, for as long as I'm a developer now, I never needed to do that patching thing
But as I tried it, I recognized it is not difficult at all, so here you can find it:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=416211
About the UIComponent approach: By collecting the UIComponent items, you suggest, that I use the bundle activator (or any place, where I retrieved a BundleContext in the first place ) to implement sth. like this:
public class Activator implements BundleActivator {
private static BundleContext context;
static BundleContext getContext() {
return context;
}
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
UIComponentCollector collector = new UIComponentCollectorImpl();
ServiceReference<UIComponent>[] refs = (ServiceReference<UIComponent>[]) context.getAllServiceReferences(UIComponent.class.getName(), null);
for (ServiceReference<UIComponent> ref : refs) {
UIComponent uic = context.getService(ref);
collector.registerComponent(uic);
}
context.registerService(UIComponentCollector.class, collector, null);
}
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext bundleContext) throws Exception {
context.ungetService(context.getServiceReference(UIComponentCollector.class));
Activator.context = null;
}
}
Is that correct? I'm not perfectly sure if I understood your last sentence correctly...
Greetings,
Daniel
[Updated on: Fri, 30 August 2013 07:23] Report message to a moderator
|
|
|
Re: [Best Practices] UI Strucure &amp;amp; Events [message #1097860 is a reply to message #1097808] |
Fri, 30 August 2013 08:57 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Hi Tom,
as my last post suggests I might now understand, what you ment with the service thing. (Maybe you could comment that post.)
But now: I don't know how, but I somehow broke my configuration... Maybe because I imported efxclipse Git repository, I cannot - for an unknown reason - start the OSGi application anymore. When I try to start the application, I get the following error:
!ENTRY org.eclipse.equinox.app 4 0 2013-08-30 10:54:39.801
!MESSAGE javafx/application/Application
!STACK 0
java.lang.NoClassDefFoundError: javafx/application/Application
at org.eclipse.fx.osgi.util.AbstractJFXApplication.start(AbstractJFXApplication.java:75)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.equinox.internal.app.AnyThreadAppLauncher.run(AnyThreadAppLauncher.java:26)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: javafx.application.Application cannot be found by org.eclipse.fx.osgi.util_0.9.0.201308270602
at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:455)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:421)
at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:412)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:107)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 4 more
EDIT: I started another project - same settings (as far as I can see) - and this one works.
So please: ignore this question. Since I need to write everything from scratch, it's not a big deal to have "lost" this project.
But please comment the other post.
Thank you very much!
Daniel
[Updated on: Fri, 30 August 2013 10:41] Report message to a moderator
|
|
| | | |
Re: [Best Practices] UI Strucure &amp;amp;amp; Events [message #1098179 is a reply to message #1098174] |
Fri, 30 August 2013 18:40 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
On 30.08.13 20:27, Tom Schindl wrote:
> Think the time UIComponents are registered should not matter. You should
> send out an event when a new component is registered this way you get a
> fully dynamic UI where components can come and go ;-)
>
> Tom
>
> On 30.08.13 17:39, Daniel Zimmermann wrote:
>> Ok I somehow did it. I extracted the Service interfaces as Lars Vogel
>> suggested it and put them into theire own bundle. Currently this bundle
>> does have its own small (and useless) consumer, but I will remove that,
>> soon.
>> Additionally I sorted all the start level (why is this stuff so
>> important, if everyone else in all other cases says: don't touch that!).
>> The "plugins" should most likly be started one start level prior to the
>> platform itself, as far as I can understand it. I have only tryed this
>> with one test plugin, so I need to confirm it first, before I go on...
>>
>> Anyway thank you Tom! You pushed me into the right direction and to
>> learn it the hard way ist most likly the only way to remeber it for real!
>>
>> I hope that everything else will work out better than this poor start ;)
>>
>> Greetings,
>> Daniel
>
Just to clear how I think it is done:
my.app.bundle:
+ class UIComponentCollector
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="my.app.bundle.UIComponentCollector">
<implementation class="my.app.bundle.UIComponentCollector" />
<service>
<provide interface="my.app.bundle.UIComponentCollector" />
</service>
<reference bind="registerComponent" cardinality="0..n"
interface="my.app.framework.UIComponent" name="UIComponent"
policy="dynamic" unbind="unregisterComponent"/>
</scr:component>
-----------------------------
my.app.framework
+ interface UIComponent
-----------------------------
my.app.c1.bundle
+ class Comp1 implements UIComponent
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="my.app.c1.bundle.Comp1">
<implementation class="my.app.c1.bundle.Comp1" />
<service>
<provide interface="my.app.framework.UIComponent" />
</service>
</scr:component>
-----------------------------
my.app.c2.bundle
+ class Comp2 implements UIComponent
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
name="my.app.c2.bundle.Comp2">
<implementation class="my.app.c1.bundle.Comp2" />
<service>
<provide interface="my.app.framework.UIComponent" />
</service>
</scr:component>
-----------------------------
public class UIComponentCollector {
private Vector<UIComponent> components = new Vector<>();
@Override public void registerComponent(UIComponent c) {
System.err.println("[register component] " + c.getLabel());
// FIRE EVENT or make components an IObservableList (make sure
to use the correct realm!!!!)
components.add(c);
}
@Override public void unregisterComponent(UIComponent c) {
System.err.println("[unregister component] " + c.getLabel());
components.remove(c);
}
@Override public Vector<UIComponent> getComponents() {return
components;}
}
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp; Events [message #1099761 is a reply to message #1098179] |
Mon, 02 September 2013 07:08 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Hi Tom,
and thanks for all of your advice!
I didn't know that a Service Interface obviously don't need to be a Java Interface that's why there is another interface right now. I guess my DS defintion was kind of mixed up, but when I figured it out, I didn't wanted to post them again. Currently these files look pretty much like yours, with only one exception: The UIComponentCollector is registered as beeing "dynamic" while I used the "static" value. I'm unsure, what de difference between those two in this case is, but I think this is a minor thing...
You are right about the Event mechanism, but right now when I don't specify any start level, new "plugins" are not loaded (at least my simple System.err call don't kick in, which they do, if they were loaded correctly). Could this be an effect of the "dynamic" value?
And I have to admit, that I don't understand, what you mean by making the components an IObservable list and to use a correct realm (I guess this has nothing to to with application server realms).
Nevertheless: I have something to start working with. And I will.
Thanks and greetings,
Daniel
[Updated on: Mon, 02 September 2013 09:50] Report message to a moderator
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp; Events [message #1099891 is a reply to message #1099761] |
Mon, 02 September 2013 10:56 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Another obstacle has occured
The dependecy injection is not working in every case at the moment.
When I inject the collector into my main application, it is working. If I try this at another place, it's not.
What is the precondition for the DI to work properly?
Greetings,
Daniel
EDIT:
Strike that text! I just was foolish enough to assume, that everything would work miraculously out of the box. I forgot to make use of
ContextInjectionFactory.make(RootWindowCreator.class, context);
in my case. Is there any way - without digging into the depth of the Eclipse dependecy injection mechanism - to supply other classes for DI? Such as the primary stage? Otherwise it's a bit inconvenient to only have the zero-parameter constructor (agaion: in my specific case)...
EDIT2:
I hoped, that my worst problems are gone, but this isn't true unfortunatelly. My UIComponentCollectorImpl reports, that a UIComponent was registered, but when I fetch the UIComponentCollector-Service and try to iterate over the registered Components, there is nothing in the Vector... Can this be an impact of one of the bugs, mentioned on the E4/RCP/DI-Page? http://wiki.eclipse.org/Eclipse4/RCP/Dependency_Injection
[Updated on: Mon, 02 September 2013 12:27] Report message to a moderator
|
|
| | |
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp; Events [message #1099974 is a reply to message #1099949] |
Mon, 02 September 2013 13:16 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
I'm reading your messages through thunderbird so I don't see your edit
but yes without creating instances through CIF you won't get stuff injected.
I'm not sure what you mean by "I can access the plugin", ... - what is
the plugin? I guess you need to share some code somewhere so that I can
take a look what's going wrong.
Tom
On 02.09.13 14:32, Daniel Zimmermann wrote:
> Hi Tom,
>
> yes I did that, but I read about the ContextInjectionFactory - which
> might be the reason why it didn't work. With the modified code around
> and using factory it works (see my first EDIT).
>
> But as I mentioned in my second EDIT, there is still the issue, that the
> "plugin" is getting registered, but it's not present in the injected
> UIComponentCollector for some reasons unknow to me. I guess this is not
> a problem of e(fx)clipse, so the question is, how useful it is to
> question it here at all...
>
> Greetings,
> Daniel
>
> PS: I tried it the API-way - in this case I can access the "plugin"...
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp; Events [message #1100035 is a reply to message #1099974] |
Mon, 02 September 2013 15:09 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
Hi Tom,
the problem was most likly the component.xml - or the fact that I split the stuff you did to two files. Using your file and updating the class names solved that. There is (and already were prior this change) two entries on the console about service references:
!ENTRY org.eclipse.equinox.ds 4 0 2013-09-02 17:03:08.111
!MESSAGE Could not bind a reference of component UIComponent. The reference is: Reference[name = UIComponent, interface = my.service.UIComponent, policy = static, cardinality = 0..n, target = null, bind = registerComponent, unbind = unregisterComponent]
!ENTRY org.eclipse.equinox.ds 4 0 2013-09-02 17:03:08.113
!MESSAGE Could not bind a reference of component UIComponent. The reference is: Reference[name = UIComponent, interface = my.service.UIComponent, policy = static, cardinality = 0..n, target = null, bind = registerComponent, unbind = unregisterComponent]
This is most likly for the problematic references, you solved within that one component.xml, but I don't see the actual problem.
Right now I started with the real work and only have only few remaining bigger tasks:
a) the UIComponent interface and what items I should make available and
b) the Event implementation where I'm still a bit unsure about - but hey - I said the same about DS just a week ago and beside the Dependency Injection, this has at least become a whole lot clearer to me (although I guess I'm still on the beginners side )
Is there any particular tutorial or other page you could recommend for the EventAdmin stuff?
Thanks and have a good evening,
Daniel
PS: I'm on vacation for two days so I wont probably read any updates on this topic, so please excuse, if I'm not reacting very fast!
[Updated on: Mon, 02 September 2013 15:09] Report message to a moderator
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp; Events [message #1100078 is a reply to message #1100035] |
Mon, 02 September 2013 16:32 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Now that you use DI you can make use if IEventBroker ;-) I also blogged
about EventAdmin some time ago in context of 3.x:
http://tomsondev.bestsolution.at/2011/01/03/enhanced-rcp-how-views-can-communicate/
Tom
On 02.09.13 17:09, Daniel Zimmermann wrote:
> Hi Tom,
>
> the problem was most likly the component.xml - or the fact that I split
> the stuff you did to two files. Using your file and updating the class
> names solved that. There is (and already were prior this change) two
> entries on the console about service references:
> [code]
> !ENTRY org.eclipse.equinox.ds 4 0 2013-09-02 17:03:08.111
> !MESSAGE Could not bind a reference of component UIComponent. The
> reference is: Reference[name = UIComponent, interface =
> my.service.UIComponent, policy = static, cardinality = 0..n, target =
> null, bind = registerComponent, unbind = unregisterComponent]
>
> !ENTRY org.eclipse.equinox.ds 4 0 2013-09-02 17:03:08.113
> !MESSAGE Could not bind a reference of component UIComponent. The
> reference is: Reference[name = UIComponent, interface =
> my.service.UIComponent, policy = static, cardinality = 0..n, target =
> null, bind = registerComponent, unbind = unregisterComponent]
> [code/]
>
> This is most likly for the problematic references, you solved within
> that one component.xml, but I don't see the actual problem.
>
> Right now I started with the real work and only have only few remaining
> bigger tasks:
> a) the UIComponent interface and what items I should make available and
> b) the Event implementation where I'm still a bit unsure about - but hey
> - I said the same about DS just a week ago and beside the Dependency
> Injection, this has at least become a whole lot clearer to me (although
> I guess I'm still on the beginners side ;) )
>
> Is there any particular tutorial or other page you could recommend for
> the EventAdmin stuff?
>
> Thanks and have a good evening,
> Daniel
>
> PS: I'm on vacation for two days so I wont probably read any updates on
> this topic, so please excuse, if I'm not reacting very fast!
|
|
| | | | |
Re: [Best Practices] UI Strucure &amp;amp;amp; Events [message #1102120 is a reply to message #1102100] |
Thu, 05 September 2013 11:44 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
About the IEventBroker: I tried to inject it, but I only raise an exception, when trying...
Caused by: org.eclipse.e4.core.di.InjectionException: Unable to process "RootController.eventBroker": no actual value was found for the argument "IEventBroker".
at org.eclipse.e4.core.internal.di.InjectorImpl.reportUnresolvedArgument(InjectorImpl.java:412)
at org.eclipse.e4.core.internal.di.InjectorImpl.resolveRequestorArgs(InjectorImpl.java:403)
at org.eclipse.e4.core.internal.di.InjectorImpl.inject(InjectorImpl.java:108)
at org.eclipse.e4.core.internal.di.InjectorImpl.inject(InjectorImpl.java:84)
at org.eclipse.e4.core.contexts.ContextInjectionFactory.inject(ContextInjectionFactory.java:73)
at ch.cnlab.swag.platform.app.ui.RootWindowCreator.createWindow(RootWindowCreator.java:74)
at ch.cnlab.swag.platform.app.MainApplication.run(MainApplication.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:56)
... 17 more
As far as I can see, all dependecies (and more) are specified:
org.eclipse.osgi;bundle-version="3.9.0",
org.eclipse.osgi.services;bundle-version="3.3.100",
org.eclipse.equinox.app,
org.eclipse.equinox.ds;bundle-version="1.4.100",
org.eclipse.equinox.event;bundle-version="1.3.0",
org.eclipse.equinox.util;bundle-version="1.0.500",
org.eclipse.e4.core.contexts;bundle-version="1.3.0",
org.eclipse.e4.core.di;bundle-version="1.3.0",
org.eclipse.e4.core.services;bundle-version="1.1.0",
org.eclipse.fx.javafx,
org.eclipse.fx.osgi.util,
org.eclipse.fx.core.databinding,
org.eclipse.fx.ui.databinding,
org.eclipse.fx.ui.di,
org.eclipse.fx.ui.theme;bundle-version="0.9.0"
Can this be a result of problems with some start levels?
|
|
| | | | | | | | | |
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp; Events [message #1105130 is a reply to message #1105101] |
Mon, 09 September 2013 12:05 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
A little late: I was doing some trial and error stuff, while writing this post. So by now you have already answered some question that I had.
And you already did with giving me the hint about using your provided Logger.
And thank you for giving me the loggers package
Here the (slightly outdated) post:
--------------------------------------------------------------------------------
Just found this thread:
http://www.eclipse.org/forums/index.php/t/245307/
It looks like the posts you and the other guy did on this thread would provide a solution, if I do this "early enough" - say in the Activator of my bundle.
In this case I wouldn't need the first lines, because I already have the context, but I don't fully understand, how this would solve the issue, because it could trigger a NullPpointer access in the EventBroker implementation or am I wrong?
Update: I tried the approach I mentioned. As I thought, the Activator is a bad idea - I guess this is because the whole thing has nothing to do with OSGi, so it is the "wrong" place. I added the line "context.set(org.eclipse.e4.core.services.log.Logger.class, null);" to my MainApplication (the JFX starter) and it works.
Update2: It's a pitty that I couldn't find any hint, that the Events topics are not allowed to contain Dots. Also I was suprised to learn, that the approach "@Inject @Optional handle(@UIEventTopic(FOO) String bar);" doesn't work (in my case), but "@Inject handle(@Optional @UIEventTopic(FOO) String bar);" does. The mysteries of Equinox
Daniel
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp; Events [message #1105284 is a reply to message #1105130] |
Mon, 09 September 2013 16:25 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
I stumbled (yes I know: I use that word far to often...) accross another inconveniece while firing of events:
In my plugins fxml controller classes I fire something like this, to trigger a tab to open in another part of the apps UI:
@FXML
public void handleAdminUIButton(ActionEvent event) {
UIEvent evt = new UIEvent(UIComponentImpl.OPEN_ADMIN);
broker.send(evt.getName(), evt);
}
UI Event is obviously just a wrapper containing the name and some data (this is optional and by default null).
The "platform" reacts by implementing the following method in one of its classes:
@SuppressWarnings("restriction")
@Inject
private void triggerOpenContent(@Optional @EventTopic(UIBaseEvents.OPEN_ALL) Object event) {
System.err.println("trigger opening a tab: " + event);
if (event == null) {
return;
}
if (event instanceof UIEvent) {
final UIEvent evt = (UIEvent) event;
for (final UIComponent component : collector.getComponents()) {
boolean trigger = false;
for (String evtName : component.getEventNames()) {
if (evt.getName().equals(evtName)) {
trigger = true;
break;
}
}
if (trigger) {
System.err.println("trigger opening a tab: " + evt.getName());
Platform.runLater(new Runnable() {
@Override
public void run() {
UITabComponent tab = component.updateTab(context.get(Stage.class), controller.getTabPaneContent(), evt.getName(), evt.getData());
if (tab == null) {
component.openTab(context.get(Stage.class), controller.getTabPaneContent(), evt.getName(), evt.getData());
}
}
});
}
}
}
}
Ugly code, I know...
The problem is: When I do this with only one "UIComponent"-plugin within the plugin mechanism, everythings works as expected. When I add another one I can trigger this for the first plugin, but when I switch to the other ones (my navigation is a left handed accordion, so I do the switch literally), in most of the cases (ca. 75% or more) no event is fired at all (even when switching back to the other plugin).
I debuged it and only saw, that the events are still triggered (the first code clock), but never reaches the listener.
And, of course: I have no clue...
Daniel
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp;amp; Events [message #1105294 is a reply to message #1105284] |
Mon, 09 September 2013 16:37 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
Hi,
I have no clue why it is not working, but let me check one thing for you
because the e4 framework sets some very special static on bootstrapping.
Can you file a bug and if you have time maybe you can attach a simple
set of samples to reproduce it?
Tom
On 09.09.13 18:25, Daniel Zimmermann wrote:
> I stumbled (yes I know: I use that word far to often...) accross another
> inconveniece while firing of events:
> In my plugins fxml controller classes I fire something like this, to
> trigger a tab to open in another part of the apps UI:
>
> @FXML
> public void handleAdminUIButton(ActionEvent event) {
> UIEvent evt = new UIEvent(UIComponentImpl.OPEN_ADMIN);
> broker.send(evt.getName(), evt);
> }
>
> UI Event is obviously just a wrapper containing the name and some data
> (this is optional and by default null).
>
> The "platform" reacts by implementing the following method in one of its
> classes:
>
> @SuppressWarnings("restriction")
> @Inject
> private void triggerOpenContent(@Optional
> @EventTopic(UIBaseEvents.OPEN_ALL) Object event) {
> System.err.println("trigger opening a tab: " + event);
> if (event == null) {
> return;
> }
> if (event instanceof UIEvent) {
> final UIEvent evt = (UIEvent) event;
> for (final UIComponent component : collector.getComponents()) {
> boolean trigger = false;
> for (String evtName : component.getEventNames()) {
> if (evt.getName().equals(evtName)) {
> trigger = true;
> break;
> }
> }
> if (trigger) {
> System.err.println("trigger opening a tab: " +
> evt.getName());
> Platform.runLater(new Runnable() {
> @Override
> public void run() {
> UITabComponent tab =
> component.updateTab(context.get(Stage.class),
> controller.getTabPaneContent(), evt.getName(), evt.getData());
> if (tab == null) {
> component.openTab(context.get(Stage.class),
> controller.getTabPaneContent(), evt.getName(), evt.getData());
> }
> }
> });
> }
> }
> }
> }
>
> Ugly code, I know...
>
> The problem is: When I do this with only one "UIComponent"-plugin within
> the plugin mechanism, everythings works as expected. When I add another
> one I can trigger this for the first plugin, but when I switch to the
> other ones (my navigation is a left handed accordion, so I do the switch
> literally), in most of the cases (ca. 75% or more) no event is fired at
> all (even when switching back to the other plugin).
> I debuged it and only saw, that the events are still triggered (the
> first code clock), but never reaches the listener.
>
> And, of course: I have no clue...
>
> Daniel
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp;amp; Events [message #1105300 is a reply to message #1105294] |
Mon, 09 September 2013 16:47 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
You can try to do the following, in the main method of your application
you call:
@PostConstruct
void run(
IApplicationContext applicationContext,
javafx.application.Application jfxApplication,
Stage primaryStage,
IEclipseContext appContext) {
ContextInjectionFactory.setDefault(appContext);
// proceed
}
Tom
On 09.09.13 18:37, Tom Schindl wrote:
> Hi,
>
> I have no clue why it is not working, but let me check one thing for you
> because the e4 framework sets some very special static on bootstrapping.
>
> Can you file a bug and if you have time maybe you can attach a simple
> set of samples to reproduce it?
>
> Tom
>
> On 09.09.13 18:25, Daniel Zimmermann wrote:
>> I stumbled (yes I know: I use that word far to often...) accross another
>> inconveniece while firing of events:
>> In my plugins fxml controller classes I fire something like this, to
>> trigger a tab to open in another part of the apps UI:
>>
>> @FXML
>> public void handleAdminUIButton(ActionEvent event) {
>> UIEvent evt = new UIEvent(UIComponentImpl.OPEN_ADMIN);
>> broker.send(evt.getName(), evt);
>> }
>>
>> UI Event is obviously just a wrapper containing the name and some data
>> (this is optional and by default null).
>>
>> The "platform" reacts by implementing the following method in one of its
>> classes:
>>
>> @SuppressWarnings("restriction")
>> @Inject
>> private void triggerOpenContent(@Optional
>> @EventTopic(UIBaseEvents.OPEN_ALL) Object event) {
>> System.err.println("trigger opening a tab: " + event);
>> if (event == null) {
>> return;
>> }
>> if (event instanceof UIEvent) {
>> final UIEvent evt = (UIEvent) event;
>> for (final UIComponent component : collector.getComponents()) {
>> boolean trigger = false;
>> for (String evtName : component.getEventNames()) {
>> if (evt.getName().equals(evtName)) {
>> trigger = true;
>> break;
>> }
>> }
>> if (trigger) {
>> System.err.println("trigger opening a tab: " +
>> evt.getName());
>> Platform.runLater(new Runnable() {
>> @Override
>> public void run() {
>> UITabComponent tab =
>> component.updateTab(context.get(Stage.class),
>> controller.getTabPaneContent(), evt.getName(), evt.getData());
>> if (tab == null) {
>> component.openTab(context.get(Stage.class),
>> controller.getTabPaneContent(), evt.getName(), evt.getData());
>> }
>> }
>> });
>> }
>> }
>> }
>> }
>>
>> Ugly code, I know...
>>
>> The problem is: When I do this with only one "UIComponent"-plugin within
>> the plugin mechanism, everythings works as expected. When I add another
>> one I can trigger this for the first plugin, but when I switch to the
>> other ones (my navigation is a left handed accordion, so I do the switch
>> literally), in most of the cases (ca. 75% or more) no event is fired at
>> all (even when switching back to the other plugin).
>> I debuged it and only saw, that the events are still triggered (the
>> first code clock), but never reaches the listener.
>>
>> And, of course: I have no clue...
>>
>> Daniel
>
|
|
| |
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp;amp; Events [message #1105704 is a reply to message #1105695] |
Tue, 10 September 2013 07:25 |
Daniel Zimmermann Messages: 81 Registered: July 2009 |
Member |
|
|
I solved it - kind of.
Just to make clear how I currently implement the UI, I will try to describe my approach:
- MainApplication - the entry point of the app with the @PostConstruct method you've mentioned earlier, it calls a class, I call something like the following
- *Creator - this class gets the IEclipseContext injected (or better: it is build via ContextInjectionFactory#make(Class<?>, IEclipseContext)) and this class is doing the FXMLLoader thing and injects the context into the controller for DI
- *Controller - pretty obvious
- ...
I follow this approach througout the other plugins as well, but there the entry point is the UIComponent implementaion.
Now I simply did the following: The event listening method was within the *Creator class and I just moved it to the *Controller... é voila. My guess would be, that somehow the *Creator was either garbage collected or otherwise disposed of and since the UI is "still there" the controller is not removed and thus the listener still exists and reacts after switching betweeen the UI components.
To conclude it: I thing this is an issue of Java, the GC or something, that I stumbled over (I really should stop using this word!).
Please let me know, if this issue is still worth looking into and if I should still file a bug (somewhere).
Thank you very much for your help so far!!!
Daniel
|
|
|
Re: [Best Practices] UI Strucure &amp;amp;amp;amp;amp;amp;amp;amp; Events [message #1105730 is a reply to message #1105704] |
Tue, 10 September 2013 07:58 |
Thomas Schindl Messages: 6651 Registered: July 2009 |
Senior Member |
|
|
This event stuff can only work for classes who are created using CIF.make
Tom
On 10.09.13 09:25, Daniel Zimmermann wrote:
> I solved it - kind of.
>
> Just to make clear how I currently implement the UI, I will try to
> describe my approach:
>
>
> MainApplication - the entry point of the app with the @PostConstruct
> method you've mentioned earlier, it calls a class, I call something like
> the following
> *Creator - this class gets the IEclipseContext injected (or better: it
> is build via ContextInjectionFactory#make(Class<?>, IEclipseContext))
> and this class is doing the FXMLLoader thing and injects the context
> into the controller for DI
> *Controller - pretty obvious
> ...
>
>
> I follow this approach througout the other plugins as well, but there
> the entry point is the UIComponent implementaion.
> Now I simply did the following: The event listening method was within
> the *Creator class and I just moved it to the *Controller... é voila. My
> guess would be, that somehow the *Creator was either garbage collected
> or otherwise disposed of and since the UI is "still there" the
> controller is not removed and thus the listener still exists and reacts
> after switching betweeen the UI components.
> To conclude it: I thing this is an issue of Java, the GC or something,
> that I stumbled over (I really should stop using this word!).
>
> Please let me know, if this issue is still worth looking into and if I
> should still file a bug (somewhere).
>
> Thank you very much for your help so far!!!
> Daniel
|
|
| |
Goto Forum:
Current Time: Thu Sep 26 16:33:47 GMT 2024
Powered by FUDForum. Page generated in 0.09855 seconds
|