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.
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.
I am building a simple POS for my business. I own a little restaurant and would like to make my life easier. I have a class (main menu) that extends JPanel, this class has layout BorderLayout. The menu has a set of panel (NORTH) with button, a JList(WEST), another panel with buttons(CENTER) to change the submenus(EAST), and another buttons(SOUTH) for removing and/or modifying items on list.
When I click on modify (a button on the south panel) another panel should appear. This panel is for the most part the same as the main menu. It has a menu on the north, a list on the west, etc. The part that differs is the actions the buttons on the north and the buttons on the south perform.
My question is:
1) should I create a general class and extend to create this two menus I need
2) should I add an inner class to each extended class for the corresponding functionality of the buttons or should I create external actions.
I am always confused about how to treat events. Create external classes and pass listeners to classes or to use nested classes (but sometimes I find too many nested classes).
If you need me to post the code let me know. Is a little long, this is why I did not post it!
Much of this is opinion based, but here goes anyway...
I would suggest creating subclasses for the different menus, each extending a abstract class defining the common elements. Have them in the same package.
As for event handlers, that's trickier. Sometimes an even handler is only used in one place, in that case, an anonymous inner class (or lambda in Java 8) is the best approach. But if the same handler may be used for different events, then remember the DRY principle, and use a separate class.
In my application user gets to choose "distribution type" for a few parameters and then I create Graph and show it to him. There are 3 different types of these distributions with each of them having its own parameters ( like alpha, beta, probabilities, etc). Each parameter can have either of those distributions.
Here is the screenshot to make it clear, what I'm trying to describe:
Distribution options are contained in CardLayout, that is controlled by combobox.
When user presses the button, I need to instantiate proper domain objects for distributions. Right now, I'm just passing ComboBox item (which is enum) and CardLayouted panel to factory that chooses proper subpanel and instantiates correct object. But it seems wrong to pass around gui objects, also makes factory useless for any other situation.
But I can't think of a better way to instantiate correct object. Probably just one idea:
Let CardLayouted panel decide which panel is ontop and instantiate
proper object on request. I wouldnt need any factories for this one. But is it ok for gui object to do this kind of logic? How can I delegate to domain in a proper way?
All suggestions will be appreciated a lot!
Swing has generally good support for MVC and pushing or pulling data from a domain object to input / display controls. What I'd do is:
Instantiate the panels you put into the CardLayout with a "blank" domain object as its GUI model. (Or some sort of locator that can retrieve the model from another layer.) Then hook up change notifications on your input components that will update the domain object when the values in the input change.
Then, when it comes to persisting the domain object, just retrieve it from the form panel.
If you need to show the same model value in two controls, they should share the same model. If you need to do updates to an object being displayed from lower layers of the code, you should perform the update on the model instead of / in addition to the domain object.
what is the best way to have JFrames, JDialogs, etc that derive from a common parent but differ some, to be able to have the common parts update automatically when the parent does, but also have new components which are still easily modified in a GUI builder.
One approach I have used before is having placeholder JPanels that populate with existing isolated components at runtime, but I suspect that this is not the best way.
Example frame visual inheritence:
Don't use a GUIBuilder unless you creating some sort of prototype or other throw away code.
Have the components that need to update automatically setup as listeners for some sort of change event. Once an update is needed fire of an "Event" to each listener.
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.