I'm developing this application where you can put text and drawings in a page. My application is in MVC pattern, and I need all the model parts, text and shapes to be of the same notion. They all extend an abstract ReportElement clas, for example.
But the problem is I crate a JPanel for every shape in the page, but to handle text I need to use JTextArea or something. To render the elements the View directly gets the report elements list from the Model and draws one by one. How can I distinguish a text element without hurting the MVC pattern.
I mean, it's impossible, right? I don't know, any ideas?
I think you're looking for the "Factory Pattern"
You need to have a wrapper method that returns a JComponent based in your own ReportElement conditions.
I would handle this situation by building a factory method that produces the right type of Swing component for any given ReportElement, like this:
public static JComponent buildViewForReportElement(ReportElement element)
Inside this method, you will need to actually inspect the ReportElement objects to see what type of component to build. This inspection might mean checking a field or a flag on each object, or might even mean using instanceof to distinguish different subclasses of ReportElement from one another.
Note that inspecting ReportElement objects like this violates the philosophy of object-oriented programming. A simple "object-oriented" solution would require all of your ReportElement objects to have a buildView() or getView() method, and so your GUI code could just call getView() on every ReportElement without knowing which implementation of getView() was actually being called.
Unfortunately, the object-oriented solution forces you to mix your view code with your model code, and it's good that you are trying to keep the two separate. That's why I would advocate keeping the GUI-building code out of ReportElement objects and instead using a factory method to build the right view for any given ReportElement.
Related
I have a panel, let's call it detailsPanel, which holds a Person reference and displays its field values in the following manner:
Name: person.getName ();
Surname: person.getSurname ();
Emain: person.getEmail ();
.... .......
.... .......
And so on. I will use JLabels (correctly aligned using a GridBagLayout) to show each (fieldName, fieldValue). I have a lot of fields to display.
The problem is that the panel which shows the details must be always visible, i.e it will not be shown in a modal JDialog, so that i could create the panel by simply reading my Person object fields at the panel creation.
The panel must always be visible, and its Person reference will change when the user selects a different row in a Person list. This means i will call a method to update its state, something like:
detailsPanel.setPerson (aPerson);
Now, i'm wondering how i should update all the fields. Should i keep a reference to all the JLabels which show the values, and use setText(value) on each of them when i update the panel, or would it be better to override getText() method for every label, returning the correct field value, so that in the update method i would only repaint the panel, and the text would automatically change when the getter method is used on a different Person object?
Any suggestion is appreciated!
Since this is UI stuff which is usually called almost never (relative to how often things are called in other computation) you don't need to worry about efficiency at all. Just do what you think is the most elegant solution. There are three options That quickly come to my mind. They are ordered from quick and static to elegant and reusable:
Quick and dirty: create your constructor and make everything look nice. Then move everything from the constructor to a separate init() method and every time the entities change, you just call removeAll(); and then init() again.
As you suggested, keep a reference to all labels and use the setPerson() method to update all panels. Then call this method in the constructor (this is arguably the most common solution).
As you suggested, build your own extension of JLabel. This new class should either have an update() method which is to be called when things change, or have it set its own listeners to ensure that it gets notified of any relevant change.
If you are planning to create a single panel which is supposed to display all kinds of objects, you could have those object implement an interface called Displayable which gives you generic access to all its values and maybe even listeners to each value. An alternative to the Displayable interface is to use reflection and use annotations to allow the panel to get its values for display.
Please note that the most elegant solution is - contrary to what some people may tell you - not always the best for any situation. How much maintenance do you expect there to be in the future? How big is the application? Will you ever hand off the code to someone else? All these and more need to be considered to decide how "nice" you want your solution to be.
Both the Book of Vaadin and the Vaadin training course recommend using acom.vaadin.ui.CustomComponent to contain a Layout.
I can understand this in pure theory, to encapsulate the contents without needlessly exposing a specific layout such as GridLayout or HorizontalLayout. Encapsulating has benefits of:
Encouraging de-coupling between classes
Makes it easier to change the layout without having to change the declarations in the outer class.
But in terms of practicality, I assume the rendering of a CustomComponent means extra HTML/CSS layout instructions such as perhaps an another div. The last thing Vaadin rendering needs is yet another layering of HTML structure.
I wonder if this might be old folklore. Perhaps using the visual composing tool in Eclipse accepts only CustomComponent objects rather than Layout objects? (Just a wild guess, I have no knowledge)
➤ Alternatively, why not just declare in the outer class a reference variable of type com.vaadin.ui.Layout to get the same encapsulation?
➤ Am I exaggerating the impact of adding a CustomComponent to Vaadin rendering?
➤ Is there some other benefit of CustomComponent which I’ve failed to perceive?
You can compose the content of a CustomComponent with the Visual Designer. This saves a lot of time in the development process
The main advantage of the CustomLayout is, that you can place your components inside HTML code which you otherwise can't generate via vaadin means.
If this adds more div/html as with native Layouts depends on the specific case.
We ususally use it only when a clean Vaadin only solution would introduce more components/div's or is not possible to implement.
The second idea is the separation of layout and logic, which can be implemented partially with this Layout. You just specify which components you have and then a UI designer (in theorie) could make your HTML code, with the correct blocks where your components will be placed.
In real life I do not find this a real advantage, since the whole CSS, sizing etc. is anyway done with vaadin.
I'm writing an RCP-Application and trying to use databinding to link the controls of the GUI with the model. This includes for example binding data to a table.
As far as I understood, org.eclipse.jface.databinding.viewers.ViewerSupport is the recommended method to bind a model to a table viewer. This will however only allow me to put the data as text into the table. I'd also like to change the foreground and background color aswell as the font of some cells, depending on other observables. I'd also be happy if I could somehow get a ITableFontProvider or ITableColorProvider into what ViewerSupport.bind(...) produces.
So far I've not found a nice way to do that. I could copy the contents of ViewerSupport.bind() and override the LabelProvider with my own class. This seems a bit messy.
I could also after calling ViewerSupport.bind retrieve the LabelProvider and replace it with a delegating LabelProvider which also implements ITableFontProvider and ITableColorProvider. This leaves me creating a lot of methods that do nothing but delegate things to another object. Not very elegant aswell.
All of that doesn't seem so nice. Any idea how to do it in an elegant way? Am I overlooking some factory class to do that?
ViewerSupport just provides simplified methods based on the various data binding content and label providers. It is perfectly acceptable to use these content and label providers directly when ViewerSupport does not provide what you want.
For example, ViewerSupport.bind(StructuredViewer viewer, IObservableList input,
IValueProperty[] labelProperties) is just:
ObservableListContentProvider contentProvider = new ObservableListContentProvider();
if (viewer.getInput() != null)
viewer.setInput(null);
viewer.setContentProvider(contentProvider);
viewer.setLabelProvider(new ObservableMapLabelProvider(Properties
.observeEach(contentProvider.getKnownElements(),
labelProperties)));
if (input != null)
viewer.setInput(input);
So you could just use this code but with a sub-class of ObservableMapLabelProvider with your font and color providers.
So I'm having one super class, Block, that extends Composite and uses the UIBinder to make the layout
class Block extends Composite
I want to create two subclasses for that one, that each have different set of icons that have to be added. For example an InactiveBlock and an ActiveBlock.
My problem here is that I want the layout of both blocks (the icons, and some buttons,labels) to be made through the UIBinder aswell, and then to add that UIBinder (and it's events) to be added to the main Block.
Obviously I can't do something like
class ActiveBlock extends Block, Composite
add(initWidget(UIBinder.create(this)));
How could I accomplish this?
(ps if my question is not clear enough, please do tell so I can elaborate)
I would make it a single class with a constructor method having boolean as an input parameter (active/inactive).
So you can define all the common fields and methods in the class, like event handlers, images, etc.
And then use the constructor method to add the elements and handlers to the basic widget. Something will be added to all instances, something depending on whether it's active or not.
In this case you won't end up with duplicated code, still will have a benefit of using uibinder, and eventually your code will be simple enough for reading.
I have a GUI with nested panels(tabbed with nested panels and etc). I need to pass domain object to deeply nested panel. I can think of two ways:
Instantiate all gui objects in one place, like frame class. That
would make passing domain objects dead simple, but Frame class will
be huge and hardly maintanable.
Each panel has its own class, where we instantiate and layout its
components. Now its easy to maintain and classes are clean, but how
do I pass down the chain my domain objects? I dont want to chain-pass
them through constructors of panels that shouldn't even know their
existance. And top level panels would have a ton of these objects to
start with.
Niether way seems like a soulution. How do you usually aproach this?
When I put together a Java Swing GUI, I have a data model for each major GUI element. Note that this isn't an MVC pattern. This is more like a local MV pattern. If you want, you can consider GUI element listeners as the "controller".
Each panel has its own class, where we instantiate and layout its
components. Now its easy to maintain and classes are clean, but how
do I pass down the chain my domain objects?
You have the right idea, although you shouldn't have to do much passing.
My JFrame (or JApplet) will have an associated model class of global type fields. An instance of this model class will usually be passed along to the children elements. This is to allow children elements to react properly when a menu option is selected (as an example)
My JPanel(s) will have an associated model class that maintains the state of text or button children elements.
More complicated children elements, like a JList or a JTree, already have an associated data model. I will probably wrap these associated data models into the JPanel model class for convenience.
The children elements will trigger some sort of selection or action listener. Some of these listeners might need access to model classes besides the model class associated with the parent. In this case, you're going to have to pass the instances of your model classes to the listeners.
This is sort of a Chain of Responsibility pattern. What I would do is have something that creates a map with all of your display objects in it and pass it from constructor to constructor. That way every instance can take what it needs from the map without caring what else is there.