how to auto fill with composite pattern, polymorphism? - java

Hi I'm working with composite pattern. I'm going to use this example of Head First Design Pattern to explain https://github.com/bethrobson/Head-First-Design-Patterns/tree/master/src/headfirst/designpatterns/composite/menuiterator
Imagine that every menu and submenu have an Id to indentify, it is 10 length.
Something like this
0100000000 menu_1
0101000000 menu_1's subMenu_1
0102000000 menu_1's subMenu_2
0102010000 subMenu_2's subMenu_3
0200000000 menu_2
And what I have at random is the menu item, but it has an ID, which is a Menu ID to which it belongs. For example
0101000000 menuItem_1
0200000000 menuItem_2
So MenuItem 1 belongs to Menu 1's SubMenu 1 and MenuItem 2 belongs to Menu 2.
It would be coded like this.
menu_1.add(subMenu_1);
subMenu_1.add(menuItem_1);
menu_2.add(menuItem_2);
Now how am I filling the menus?
What I'm doing because of I get only the MenuItems, is that I'm cutting the Id to determine where it belongs.
For example you can see that there two Menus, Menu 1 (0100000000) and Menu 2 (0200000000) so I have to cut the first 2 Strings.
I'm coding like this:
class AllMenus implements MenuComponent {
MenuComponent menu_1
MenuComponent subMenu_1
MenuComponent subMenu_2
MenuComponent subMenu_3
MenuComponent menu_2
#Override
add(MenuComponent menu) {
if(menu instanceof Menu) {
super.add(menu)
} else if(menu instanceof MenuItem) {
String subId = menuItem.getId().subString(0,2)
if(subId.equals("01")) {
if(menu_1 == null) {
menu_1 = new Menu();
add(menu_1);
}
subId = menuItem.getId().subString(0,4);
if(subId.equals("0101")) {
if(subMenu_1 == null) {
subMenu_1 = new Menu();
menu_1.add(subMenu_1);
}
subMenu_1.add(menuItem);
} else if(subId.equals("0102")) {
if(subMenu_2 == null) {
subMenu_2 = new Menu();
menu_1.add(subMenu_2);
}
subId = menuItem.getId().subString(0,6);
if(subId.equals("010201")) {
if(subMenu_3 == null) {
subMenu_3 = new Menu();
subMenu_2.add(subMenu_3);
}
subMenu_3.add(menuItem);
}
}
} else if(subId.equals("02") {
if(menu_2 == null) {
menu_2 = new Menu();
add(menu_2);
}
menu_2.add(menuItem);
}
}
}
}
This is for every MenuItem I get. So as you can see this code is to long just for four Menus,imagine thousands of menu, how can it get better?.
I have read that i should use polymorphism to something that repeat, but I don't know how in this case.

If I understand your question properly, I think there's too much assumption of the eventual structure in your code.
In general, number literals in your code should be treated with suspicion - e.g.
if(subId.equals("010201")
... because it looks like configuration, not code. Of course it's fine to put "configuration" in your code, and sometimes it's practical for that configuration to be program code rather than XML/CSV/JSON/etc. -- but even then, it's good to have a logical separation between a "config" class and a "code" class. For example your "config" class might just contain a method that returns arrays of strings:
public class MenuConfig() {
public String[][] configs() {
return new String[][] {
new String[] {"0100000000", "Main menu"},
new String[] {"0101000000", "Settings"},
new String[] {"0101010000", "Look and feel"},
new String[] {"0102000000", "My account"},
// etc.
}
}
}
You're looking to create a tree of submenus -- look for inspiration in code to manipulate trees (e.g. binary trees) -- see how simple the code is and how it doesn't make assumptions beyond the fact that each node has zero or more subnodes.
You're already using polymorphism -- your menus and submenus conform to a common type (I can't tell from your code whether they all have the same concrete type, but in principle I might expect you to have a variety of classes that implement MenuComponent.
Your code to process one menu just needs to parse the ID to work out where it's supposed to go, then find the place it needs to go, and insert it:
(I'm presenting the IDs with hyphens to make it easier to read)
// split "01-02-03-00-00" into [1,2,3] -- ignoring trailing zeros
List<Integer> path = parse(currentMenu.getId());
MenuComponent m = rootMenuComponent;
while(path.size() > 1) {
m = m.getSubMenu(path.remove(0));
}
m.add(path.remove(0), currentMenu());
This simple algorithm assumes that menus are added in the right order -- that is you must have handled 01-02-00-00-00 before 01-02-01-00-00, or you'll get a null pointer.
If you can't live with that constraint, you need to define what could happen, and decide how to deal with it.
Actually with your current scheme, sorting the keys alphabetically should be sufficient
If they're just going to come out-of-order, you could treat the to-do-list of menus to be added as a queue. If a particular item can't yet be added, put it to the back of the queue and retry after processing the rest.
If you want it not to be necessary to explicitly define intermediate menus, then when m.getSubMenu(subMenuNum) returns null (because you've implicitly "defined" it in the middle of a path) you'll need to create the missing menu at that point.
If you want it to be possible to define the same menu more than once (maybe both implicitly and explicitly) then you need MenuComponent.add() to handle that case, either by merging or overwriting, depending on your requirement.
Assembling a graph of nodes like this is what Spring dependency-injection does -- handling building the graph in order, when the dependencies are defined in arbitrary order. If your aim is study, keep building your own. If you just want build a composite of menus, consider using Spring (or some other DI framework).

Related

JavaFX TreeItem css style for different class field

I have TreeView filled by my own tree. In class Node I have field "type" which is one of NodeType. The problem is that I want have style for each type of NodeType, e.g. "type1" text color should be green, "type2" text color should be red. I'm new in javaFX. I found solution by james-d ( https://github.com/james-d/heterogeneous-tree-example ), but in this example css style depends on the class name, how can I make it for class field ?
View of TreeView
My understanding is you want a TreeCell that styles differently depending on the NodeType of the Node contained within the TreeItem of said TreeCell. All via CSS. Am I correct?
Assuming I am correct, there are 2 ways I can think of to accomplish this; both of which work best if there is a small number of known NodeTypes. The first involves the use of PseudoClass and the second uses the same strategy as the JavaFX Chart API.
First Option
Create a custom TreeCell that is tailored to using your Node type (i.e. specify the generic signature appropriately). In this custom TreeCell you declare as many PseudoClass static final fields as you need; one for each NodeType. Then you observe the NodeType of the whatever Node is currently displayed in the TreeCell and update the PseudoClass states accordingly.
Here is an example assuming NodeType is an enum that has two constants: HAPPY and SAD.
public class CustomTreeCell<T extends Node> extends TreeCell<T> {
private static final PseudoClass HAPPY = PseudoClass.getPseudoClass("happy");
private static final PseudoClass SAD = PseudoClass.getPseudoClass("sad");
// this listener will activate/deactivate the appropriate PseudoClass states
private final ChangeListener<NodeType> listener = (obs, oldVal, newVal) -> {
pseudoClassStateChanged(HAPPY, newVal == NodeType.HAPPY);
pseudoClassStateChanged(SAD, newVal == NodeType.SAD);
};
// use a weak listener to avoid a memory leak
private final WeakChangeListener<NodeType> weakListener = /* wrap listener */;
public CustomTreeCell() {
getStyleClass().add("custom-tree-cell");
itemProperty().addListener((obs, oldVal, newVal) -> {
if (oldVal != null) {
oldVal.nodeTypeProperty().removeListener(weakListener);
}
if (newVal != null) {
newVal.nodeTypeProperty().addListener(weakListener);
// need to "observe" the initial NodeType of the new Node item.
// You could call the listener manually to avoid code duplication
pseudoClassStateChanged(HAPPY, newVal.getNodeType() == NodeType.HAPPY);
pseudoClassStateChanged(SAD, newVal.getNodeType() == NodeType.SAD);
} else {
// no item in this cell so deactivate all PseudoClass's
pseudoClassStateChanged(HAPPY, false);
pseudoClassStateChanged(SAD, false);
}
});
}
}
Then in your CSS file you can use:
.custom-tree-cell:happy {
/* style when happy */
}
.custom-tree-cell:sad {
/* style when sad */
}
Second Option
Do what the JavaFX Chart API does when dealing with multiple series of data. What it does is dynamically update the style class of the nodes depending on the series' index in a list (e.g. .line-chart-series-data-<index> <-- probably not exactly this).
/*
* Create a custom TreeCell like in the first option but
* without any of the PseudoClass code. This listener should
* be added/removed from the Node item just like weakListener
* is above.
*/
ChangeListener<NodeType> listener = (obs, oldVal, newVal) -> {
// You have to make sure you keep "cell", "indexed-cell", and "tree-cell"
// in order to keep the basic modena styling.
if (newVal == NodeType.HAPPY) {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell", "custom-tree-cell-happy");
} else if (newVal == NodeType.HAPPY) {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell", "custom-tree-cell-sad");
} else {
getStyleClass().setAll("cell", "indexed-cell", "tree-cell"); // revert to regular TreeCell style
}
};
Then in CSS:
.custom-tree-cell-happy {
/* styles */
}
.custom-tree-cell-sad {
/* styles */
}
Both of these options are really only viable when there is a small set of known types. It might become unmaintainable when you have something like 10+ NodeTypes. It becomes pretty much impossible if the number of NodeTypes is dynamic at runtime.
It might be easier to have NodeType, or some intermediate class/data structure, know what color the text should be and set the color programmatically based on the NodeType.
Note: I quickly typed up the code in my answer and did not test it. There may be compiler errors, runtime exceptions, or logic errors in my code.
Edit
Something else came to mind. My code above assumes that NodeType is held in a property and can be changed during runtime. If NodeType is static (unchanging) for each Node then the code can be vastly simplified. Instead of using any listeners you can simple override the following method declared in javafx.scene.control.Cell:
protected void updateItem(Node item, boolean empty)
This method is called every time a new item is set on the cell. Read the documentation, however, as overriding this method requires certain things from the developer (such as calling the super implementation).

Java class: limit instance variable to one of several possible values, depending on other instance variables

I am sorry for the vague question. I am not sure what I'm looking for here.
I have a Java class, let's call it Bar. In that class is an instance variable, let's call it foo. foo is a String.
foo cannot just have any value. There is a long list of strings, and foo must be one of them.
Then, for each of those strings in the list I would like the possibility to set some extra conditions as to whether that specific foo can belong in that specific type of Bar (depending on other instance variables in that same Bar).
What approach should I take here? Obviously, I could put the list of strings in a static class somewhere and upon calling setFoo(String s) check whether s is in that list. But that would not allow me to check for extra conditions - or I would need to put all that logic for every value of foo in the same method, which would get ugly quickly.
Is the solution to make several hundred classes for every possible value of foo and insert in each the respective (often trivial) logic to determine what types of Bar it fits? That doesn't sound right either.
What approach should I take here?
Here's a more concrete example, to make it more clear what I am looking for. Say there is a Furniture class, with a variable material, which can be lots of things, anything from mahogany to plywood. But there is another variable, upholstery, and you can make furniture containing cotton of plywood but not oak; satin furniture of oak but not walnut; other types of fabric go well with any material; et cetera.
I wouldn't suggest creating multiple classes/templates for such a big use case. This is very opinion based but I'll take a shot at answering as best as I can.
In such a case where your options can be numerous and you want to keep a maintainable code base, the best solution is to separate the values and the logic. I recommend that you store your foo values in a database. At the same time, keep your client code as clean and small as possible. So that it doesn't need to filter through the data to figure out which data is valid. You want to minimize dependency to data in your code. Think of it this way: tomorrow you might need to add a new material to your material list. Do you want to modify all your code for that? Or do you want to just add it to your database and everything magically works? Obviously the latter is a better option. Here is an example on how to design such a system. Of course, this can vary based on your use case or variables but it is a good guideline. The basic rule of thumb is: your code should have as little dependency to data as possible.
Let's say you want to create a Bar which has to have a certain foo. In this case, I would create a database for BARS which contains all the possible Bars. Example:
ID NAME FOO
1 Door 1,4,10
I will also create a database FOOS which contains the details of each foo. For example:
ID NAME PROPERTY1 PROPERTY2 ...
1 Oak Brown Soft
When you create a Bar:
Bar door = new Bar(Bar.DOOR);
in the constructor you would go to the BARS table and query the foos. Then you would query the FOOS table and load all the material and assign them to the field inside your new object.
This way whenever you create a Bar the material can be changed and loaded from DB without changing any code. You can add as many types of Bar as you can and change material properties as you goo. Your client code however doesn't change much.
You might ask why do we create a database for FOOS and refer to it's ids in the BARS table? This way, you can modify the properties of each foo as much as you want. Also you can share foos between Bars and vice versa but you only need to change the db once. cross referencing becomes a breeze. I hope this example explains the idea clearly.
You say:
Is the solution to make several hundred classes for every possible
value of foo and insert in each the respective (often trivial) logic
to determine what types of Bar it fits? That doesn't sound right
either.
Why not have separate classes for each type of Foo? Unless you need to define new types of Foo without changing the code you can model them as plain Java classes. You can go with enums as well but it does not really give you any advantage since you still need to update the enum when adding a new type of Foo.
In any case here is type safe approach that guarantees compile time checking of your rules:
public static interface Material{}
public static interface Upholstery{}
public static class Oak implements Material{}
public static class Plywood implements Material{}
public static class Cotton implements Upholstery{}
public static class Satin implements Upholstery{}
public static class Furniture<M extends Material, U extends Upholstery>{
private M matrerial = null;
private U upholstery = null;
public Furniture(M matrerial, U upholstery){
this.matrerial = matrerial;
this.upholstery = upholstery;
}
public M getMatrerial() {
return matrerial;
}
public U getUpholstery() {
return upholstery;
}
}
public static Furniture<Plywood, Cotton> cottonFurnitureWithPlywood(Plywood plywood, Cotton cotton){
return new Furniture<>(plywood, cotton);
}
public static Furniture<Oak, Satin> satinFurnitureWithOak(Oak oak, Satin satin){
return new Furniture<>(oak, satin);
}
It depends on what you really want to achieve. Creating objects and passing them around will not magically solve your domain-specific problems.
If you cannot think of any real behavior to add to your objects (except the validation), then it might make more sense to just store your data and read them into memory whenever you want. Even treat rules as data.
Here is an example:
public class Furniture {
String name;
Material material;
Upholstery upholstery;
//getters, setters, other behavior
public Furniture(String name, Material m, Upholstery u) {
//Read rule files from memory or disk and do all the checks
//Do not instantiate if validation does not pass
this.name = name;
material = m;
upholstery = u;
}
}
To specify rules, you will then create three plain text files (e.g. using csv format). File 1 will contain valid values for material, file 2 will contain valid values for upholstery, and file 3 will have a matrix format like the following:
upholstery\material plywood mahogany oak
cotton 1 0 1
satin 0 1 0
to check if a material goes with an upholstery or not, just check the corresponding row and column.
Alternatively, if you have lots of data, you can opt for a database system along with an ORM. Rule tables then can be join tables and come with extra nice features a DBMS may provide (like easy checking for duplicate values). The validation table could look something like:
MaterialID UpholsteryID Compatability_Score
plywood cotton 1
oak satin 0
The advantage of using this approach is that you quickly get a working application and you can decide what to do as you add new behavior to your application. And even if it gets way more complex in the future (new rules, new data types, etc) you can use something like the repository pattern to keep your data and business logic decoupled.
Notes about Enums:
Although the solution suggested by #Igwe Kalu solves the specific case described in the question, it is not scalable. What if you want to find what material goes with a given upholstery (the reverse case)? You will need to create another enum which does not add anything meaningful to the program, or add complex logic to your application.
This is a more detailed description of the idea I threw out there in the comment:
Keep Furniture a POJO, i.e., just hold the data, no behavior or rules implemented in it.
Implement the rules in separate classes, something along the lines of:
interface FurnitureRule {
void validate(Furniture furniture) throws FurnitureRuleException;
}
class ValidMaterialRule implements FurnitureRule {
// this you can load in whatever way suitable in your architecture -
// from enums, DB, an XML file, a JSON file, or inject via Spring, etc.
private Set<String> validMaterialNames;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
if (!validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial());
}
}
class UpholsteryRule implements FurnitureRule {
// Again however suitable to implement/config this
private Map<String, Set<String>> validMaterialsPerUpholstery;
#Overload
void validate(Furniture furniture) throws FurnitureRuleException {
Set<String> validMaterialNames = validMaterialsPerUpholstery.get(furniture.getUpholstery();
if (validMaterialNames != null && !validMaterialNames.contains(furniture.getMaterial()))
throws new FurnitureRuleException("Invalid material " + furniture.getMaterial() + " for upholstery " + furniture.getUpholstery());
}
}
// and more complex rules if you need to
Then have some service along the lines of FurnitureManager. It's the "gatekeeper" for all Furniture creation/updates:
class FurnitureManager {
// configure these via e.g. Spring.
private List<FurnitureRule> rules;
public void updateFurniture(Furniture furniture) throws FurnitureRuleException {
rules.forEach(rule -> rule.validate(furniture))
// proceed to persist `furniture` in the database or whatever else you do with a valid piece of furniture.
}
}
material should be of type Enum.
public enum Material {
MAHOGANY,
TEAK,
OAK,
...
}
Furthermore you can have a validator for Furniture that contains the logic which types of Furniture make sense, and then call that validator in every method that can change the material or upholstery variable (typically only your setters).
public class Furniture {
private Material material;
private Upholstery upholstery; //Could also be String depending on your needs of course
public void setMaterial(Material material) {
if (FurnitureValidator.isValidCombination(material, this.upholstery)) {
this.material = material;
}
}
...
private static class FurnitureValidator {
private static boolean isValidCombination(Material material, Upholstery upholstery) {
switch(material) {
case MAHOGANY: return upholstery != Upholstery.COTTON;
break;
//and so on
}
}
}
}
We often are oblivious of the power inherent in enum types. The Java™ Tutorials clearly states "you should use enum types any time you need to represent a fixed set of constants."
How do you simply make the best of enum in resolving the challenge you presented? - Here goes:
public enum Material {
MAHOGANY( "satin", "velvet" ),
PLYWOOD( "leather" ),
// possibly many other materials and their matching fabrics...
OAK( "some other fabric - 0" ),
WALNUT( "some other fabric - 0", "some other fabric - 1" );
private final String[] listOfSuitingFabrics;
Material( String... fabrics ) {
this.listOfSuitingFabrics = fabrics;
}
String[] getListOfSuitingFabrics() {
return Arrays.copyOf( listOfSuitingFabrics );
}
public String toString() {
return name().substring( 0, 1 ) + name().substring( 1 );
}
}
Let's test it:
public class TestMaterial {
for ( Material material : Material.values() ) {
System.out.println( material.toString() + " go well with " + material.getListOfSuitingFabrics() );
}
}
Probably the approach I'd use (because it involves the least amount of code and it's reasonably fast) is to "flatten" the hierarchical logic into a one-dimensional Set of allowed value combinations. Then when setting one of the fields, validate that the proposed new combination is valid. I'd probably just use a Set of concatenated Strings for simplicity. For the example you give above, something like this:
class Furniture {
private String wood;
private String upholstery;
/**
* Set of all acceptable values, with each combination as a String.
* Example value: "plywood:cotton"
*/
private static final Set<String> allowed = new HashSet<>();
/**
* Load allowed values in initializer.
*
* TODO: load allowed values from DB or config file
* instead of hard-wiring.
*/
static {
allowed.add("plywood:cotton");
...
}
public void setWood(String wood) {
if (!allowed.contains(wood + ":" + this.upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
}
public void setUpholstery(String upholstery) {
if (!allowed.contains(this.wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.upholstery = upholstery;
}
public void setMaterials(String wood, String upholstery) {
if (!allowed.contains(wood + ":" + upholstery)) {
throw new IllegalArgumentException("bad combination of materials!");
}
this.wood = wood;
this.upholstery = upholstery;
}
// getters
...
}
The disadvantage of this approach compared to other answers is that there is no compile-time type checking. For example, if you try to set the wood to plywoo instead of plywood you won’t know about your error until runtime. In practice this disadvantage is negligible since presumably the options will be chosen by a user through a UI (or through some other means), so you won’t know what they are until runtime anyway. Plus the big advantage is that the code will never have to be changed so long as you’re willing to maintain a list of allowed combinations externally. As someone with 30 years of development experience, take my word for it that this approach is far more maintainable.
With the above code, you'll need to use setMaterials before using setWood or setUpholstery, since the other field will still be null and therefore not an allowed combination. You can initialize the class's fields with default materials to avoid this if you want.

Hiding Multiple Elements in JTable via ButtonClick

I am currently working on a tool which edits data dynamically in a JTable. I want to hide the targeted row whenever a button is clicked. Right now I am using RowFilter. Whenever the button isClicked, a new filter is created:
RowFilter<MyTableModel, Object> rowFilter = null;
try {
rowFilter = RowFilter.notFilter(RowFilter.regexFilter(((String)dataTable.getValueAt(dataTable.getSelectedRow(), 0)),0));
} catch (java.util.regex.PatternSyntaxException e) {
return;
}
sorter.setRowFilter(rowFilter);
This only works for one element each time the button is clicked. I want to stay them hidden, so you can continously hide elemtens in the table. It is important to mention that I do not want to delete the rows, just hide them.
I hope someone has an easy answer for this, looking for quite a while now.
This method sorter.setRowFilter(rowFilter); is replacing the filter every time you "add" a new filter. So, it's "forgetting" the old rules. What you have to do is edit the existing filter to include the new rules for filtering.
Check out the documentation for more details.
In any case, I extracted a part of the documentation which you should try to implement.
From RowFilter Javadoc:
Subclasses must override the include method to indicate whether the
entry should be shown in the view. The Entry argument can be used to
obtain the values in each of the columns in that entry. The following
example shows an include method that allows only entries containing
one or more values starting with the string "a":
RowFilter<Object,Object> startsWithAFilter = new RowFilter<Object,Object>() {
public boolean include(Entry<? extends Object, ? extends Object> entry) {
for (int i = entry.getValueCount() - 1; i >= 0; i--) {
if (entry.getStringValue(i).startsWith("a")) {
// The value starts with "a", include it
return true;
}
}
// None of the columns start with "a"; return false so that this
// entry is not shown
return false;
}
};
This means that the include() method is going to return true or false depending if an item should be shown.
Therefore, you should only set the RowFilter once, and reimplment the include() method to match all the rules you currently have set upon your view.

Java Swing Dynamic Field Selection

I'm not sure how to ask this question, and I'm certain that there's some kind of other solution to the problem I'm having so if anyone can point me in the right direction, I'd appreciate it.
In any case, the issue I'm having is that I have a String[] list (called "projects") that I'm using to populate a combo box. I want to use the selection from the combo box to dynamically change the form fields listed in a GUI panel.
My approach, so far, isn't dynamic enough because I will have nearly 100 possible selections from the combo box when I'm done. So far, I've been testing with 3 options in the box, but scaling it up to 100 will involve a lot of code, and I think there MUST be some other solution, right? I just don't know what that solution is.
String[] projects = {"Select a project...", "Option1", "Option2", "Option3"};
String[] Option1= {"phone", "maxphv"};
String[] Option2= {"address1", "address2", "house", "predir", "street", "strtype", "postdir", "apttype", "aptnbr"
, "city", "state", "zip"};
String[] Option3= {"phone"};
ArrayList<String> fieldslist, fieldslbllist;
Ideally, I'd like to take the name of the project selected from the projects String[] combo box and reference that name as the name of another list that contains the fields I want to display in the panel.
But I gather from reading on other questions that the name of a variable is irrelevant once the code is compiled.
At this point, I have a set of code to clear the panel and dynamically select the fields, but I still have to manually code the replacement for each of the 100 options. That's not terrible, I suppose, but I think that there is probably a better way that I am unaware of.
public void resetFields() {
fieldslist.clear();
fieldslbllist.clear();
}
public void setFields() {
if (project.getSelectedIndex() == 0) {
resetFields();
}
else if (project.getSelectedIndex() == 1) {
resetFields();
for (int i = 0; i <= Option1.length; i++) {
fieldslist.add(Option1[i]);
fieldslbllist.add(Option1[i]+"lbl");
}
}
else if (project.getSelectedIndex() == 2) {
resetFields();
for (int i = 0; i <= Option2.length; i++) {
fieldslist.add(Option2[i]);
fieldslbllist.add(Option2[i]+"lbl");
}
}
//... onward to 100
The above is just a loop that resets the display on selection of a new option in the combo box and then loops through the options in the OptionX String[] list and adds the values to the fields Array.
Is this a viable way to handle dynamic UI coding? And, is there any way to set it up so I will only have to specify which fields belong to each value and then not have to code a section for each possible project.getSelectedIndex() value in setFields()?
Use CardLayout, seen here, to change the form dynamically. Given the large number of alternatives, look for a hierarchical breakdown among the choices that might allow you to use two related controls, as shown here.

Implementing a recently used or favorites dropdown in JComboBox

I am looking for code that will add favorites / MRU type behavior to a JComboBox.
I could code this myself, but it sure seems like someone else has probably already done it.
I found the following (which looks exactly like what I want, but the source code is nowhere near complete): http://java.sys-con.com/node/36658
Any suggestions? I need to keep this relatively light, so I'd prefer to not use a component that's part of a monolithic widget library, and open source is preferred.
Consider extending DefaultComboBoxModel: override addElement() and insertElementAt() to insert at zero and remove the last element.
Addendum: Here's an example; per SO, the license is cc-wiki. I'd use Preferences to persist the entries.
class MRUComboBoxModel extends DefaultComboBoxModel {
#Override
public void addElement(Object element) {
this.insertElementAt(element, 0);
}
#Override
public void insertElementAt(Object element, int index) {
super.insertElementAt(element, 0);
int size = this.getSize();
if (size > 10) {
this.removeElementAt(size - 1);
}
}
}
What about just subclassing JComboBox and overriding the
public void addItem(Object anObject)
to give it the functionality you want?
You can just keep an internal list of items synched with the effective one, and whenever you add a new item it can check if size() >= maxItems and trim down least recent ones.
Then you should find a way to refresh an item whenever it is used. If its selection it's enough to be refreshed you can write an ItemListener that does it. Otherwise you'll need a specified external action or an observer/observable pattern..

Categories