Custom component for JList instead of just strings - java

I've been trying to freshen up on my Java knowledge and I've been building a small GUI program and I've been running into a bit of a problem.
Basically, I have a JList which I'm currently populating with strings from an object from one of my classes which implement AbstractListModel which we can call my ItemList class. It contains an ArrayList of objects of the type Item which implements Serializable.
But, what I'd like to do is rather than populate my JList with a bunch of strings I'd like to populate it with some kind of string + JTextField combination so I can see one property of each Item object while also being able to update another property by changing the JTextField.
Now, what I'm looking for is the simplest possible way of doing this, and I am assuming there is a (relatively) simple way to do this since it's such a common thing to want to do in a GUI application (although I wouldn't put it past Java and Swing to make it convoluted and complicated).
So, what is the correct way of doing this?

No need to ever use String objects. Instead:
Put Item objects in the JList.
Add a ListCellRenderer to the list, to show the Item object the most user friendly way.
When the user selects an item, show the details in a different place (I'm thinking a panel with 2 columns of labels and text fields, and two rows - one for each attribute, and perhaps a button to Save)
The edit controls would best be encapsulated in a panel that can then hidden when not required, & put in a variety of places, e.g.
Below the list
In the main part of the GUI
displayed in a JOptionPane or a (modal or not) JDialog
Here is an example of placing the 'view/edit panel' (the file details) below the selection component (the table).

Related

How can I accept a value to be passed, using a method

I am trying to select an item from the jList in one form (Home), and extract the data from the ArrayList and output the data to separate jTextFields in a different form (Details). Below is the method I'm trying to use to do this (not a lot there I know!).
public void passObjectData()
{
int i = proObjList.getSelectedIndex();
}
I know once the method is complete, I can just call it on the form load method in the next form, but I'm stuck on how to get the method correct.
I don't know what other code, if any, will be needed for your help.
I have hardcoded data into an ArrayList and have output a name to a jList. Now I want to get all of the data of one person that is stored
in the ArrayList (name, address, tel num etc) and put this information
into jTextFields.
As I understand your question this ArrayList is the undelying data structure used to fill the ListModel and you want to get the selected index from the JList to retrieve the correct object stored in that array list. In this case you can:
Have a domain class called Person to hold the person's data (name, address, etc)
Add Person objects to the ListModel.
Provide an appropriate ListCellRenderer to display the person's name.
Use JList#getSelectedValue() to get the selected Person.
Pass this selected Person object to the text field's form and update those accordingly.
Optional: attach a ListSelectionListener to the JList in order to listen for user's selection changes and do the previous step automatically.
See the first 3 points of this approach exemplified here (note: the example is using JComboBox but the same applies to JList as well).
Suggested readings
Creating a Model
Selecting Items in a List
Writing a Custom Renderer
Side note
Not sure if by forms you mean JFrames but just in case: please note that we should avoid using multiple JFrames. See this topic: The Use of Multiple JFrames, Good/Bad Practice?

Using JComboBox to change JLabels from data within same object:

I am trying to design a GUI, and I am really stuck on a certain issue, which involves using JComboBox to change data in a JLabel, but the catch is the data in the JLabel comes from object data the combo box needs.
Example: hypothetical arraylist with objects in each locale:
ArrayList<Animals> FarmAnimals = new ArrayList<Animals>();
FarmAnimals.add(new Animals("Cows", "Black"));
FarmAnimals.add(new Animals("Pigs", "Pink");
FarmAnimals.add(new Animals("Sheep", "White"));
Now, I want to populate the JComboBox with "Cows", "Pigs", and "Sheep", which is easily done with making a string array of the values. The problem is that, when I, hypothetically, select "Cows", I want a color JLabel to display "Black", "Pink", and "White" respectively when chosen: ideally from the object data within the array (just in case I have more data for Cows or whatever like paw size or loudness of animal noise that I'd like to input later).
Is there any way to get an ItemListener to do this, or at least is there a tutorial that shows how to directly influence JLabel data from objects associated with what's in the JComboBox? Or am I just being stupid and there's a much better way of doing it? Thanks.
This might be a better example:
http://pokemonshowdown.com/damagecalc/
Notice that when you change the EV's or the IV's, or if you change the pokemon, the stats on the side directly change with respect to the Pokemon chosen and the change in the EV & IV inputs. I want this behavior in the GUI I'm making (stats change directly based on inputs, which I assume are directly connected to object data stored for each Pokey.) but I can't seem to mimic it.
One technique here is:
Store all your Animal data in an array, as you are currently doing.
Give the Animal class a method to receive the relevant object data, in whatever form most naturally represents it (for example, if all your animal-specific data is a list of strings like colors, a String[] or a List<String> would be a good way to hold this data). Let's call this method getData().
Override Animal.toString() to return the name of the animal that you want to display in the combo box.
Now, populate the combo box with a list of animals. Use JComboBox.addItem to add each Animal directly to the combo box.
Add an action listener to the combo box. In the action listener, you may use (Animal)comboBox.getSelectedItem() to retrieve the selected Animal directly.
Now that you have the selected Animal, you can call theAnimal.getData() to get the data you want to put in the label. You can call any other methods of Animal here too.
Basically, the idea above is to take advantage of JComboBox's ability to directly store and return your actual objects. Then you can get the relevant data directly from the selected Animal, and update other GUI elements (e.g. your label) with that data accordingly.
A couple of things to note about the above:
If overriding Animal.toString() to provide a display string is not appropriate for your situation for some reason (e.g., as MadProgrammer points out in the comments, toString() is typically used for debugging output rather than information meaningful to a user), you have other options. You could, e.g., add Strings to the combo box and, if the combo box is not sorted, take advantage of the fact that the combo box indices are the same as the indices into your Animal array. Then in your action listener, you get the selected index, and look up the animal that way. Another option is to define a custom ListCellRenderer, which is beyond the scope of this answer (but information is readily available on the internet).
You also may notice that you don't actually need the separate animal array with the above approach. You could just use the combo box itself as the "array". This may be sufficient for your needs, but bear in mind that it does tie your logic very closely to the GUI, and could cause problems in more complicated applications, especially when e.g. writing unit tests, or when writing methods that expect the collection of animals (and you end up having to pass the JComboBox/ComboBoxModel itself, or copy the items out of it into a temporary array), etc.
Sorry if that was a little vague, hopefully it gets you started down the right path.

Changing the contents of a JComboBox during runtime

Alright so I'm trying to create a combo box that will update it's contents during runtime except I have no clue how to do this without receiving a bunch of errors. Is there some sort of method that I can use in order to accomplish this? For example, I have a vector that might start out with the name in drawers 1 and 2 be hi and bye. Then during runtime the program will change drawer one and two to eggs, sausage and add a third drawer with the name being computer. How can I go about changing the name on a JComboBox during runtime?
You want to clear the combobox of all entries using removeAllItems(), then re-add the items from the Vector using addItem().
The data shown in the ComboBox actually lives in its model - some subclass of ComboBoxModel.
DefaultComboBoxModel has methods for adding and removing elements. If you want to completely replace the combo box's contents at runtime, the simplest way might be to just build a new model and call theComboBox.setModel(theNewModel) with it. Also see setSelectedItem() for setting the selection.

how to create a Custom list model in Java

I'm trying to create list that shows contacts, each list item shows the name on a line, and the phone number on a second line, and maybe an image or icon. I was thinking of using two labels for that, but i can figure out how to use a custom list model to implement this.
My first attempt was to add a Panel object that contained the info i wanted in the list, then add it to an instance of the defualt list model, but that only turned up the class name in the list.
DefaultListModel Clistmodel = new DefaultListModel();//
Clistmodel.addElement(Contact);//Contact is an JPanel object
GroupList.setModel(Clistmodel);//GroupList is the List object
this didn't work out at all then i learnt that the default list model only knows how to render strings i think, so i have to create a custom list model, or a custom ListCellRenderer, i don't really know which will solve the problem.
Your question asks how to create a custom list model, however, that's not what you need (I don't think) as a DefaultListModel will work nicely for you. Rather you will need to work on the renderer. You need to create a non-GUI class to hold your information that each item will display, probably your Contact class, and then create a JList that holds this in its DefaultListModel.
The key for you will be to then create a custom list cell renderer to display the information on multiple lines -- perhaps a JTextArea, or a JPanel that holds two JLabels in a GridLayout. Please understand that the renderer does not display the actual underlying components, but something more akin to a stamped image of whatever components you're trying to display, so it will not have the full behaviors available to it as the actual component would. It will take work, but the writing a renderer section of the tutorial linked to by user714965 will show you how to do this.
Please give it a try, and then if you still are stuck, come on back with your code, your errors, and your questions, and we'll be better able to give you specific help.

GUI: Changing panels based on value of combo box

I have a question about GUI design, specifically with Java Swing and creating clean separation between presentation and model.
It's a bit difficult to describe, but essentially we have lots of reference data in our system (i.e. that would correspond to lookup tables in the DB). We want people to be able to edit them all from one screen.
So, in an ideal world what we'd like is a combo box in the top-left corner with a list of 'types' of reference data (so each corresponding to one table in the DB).
Then, when selected, a list of the data is populated below, also a filter (or search box). When one of these items is selected, the panel to the right is activated which will allow the actual data to be edited.
Now, here's the problem: each type of data we need to edit is different, so it has different fields etc. We could go with a generic solution but I'm not really a fan of them - there are lots of different validation rules for each etc, even for different clients, and it would be a nightmare to manage.
We're using the Presentation Model pattern to achieve some degree of separation between GUI code and the model but I can't think of a clean way of doing this which doesn't somehow blur the line of responsibilities a bit.
What are the ways you have solved problems like this?
[Note: apologies for the long question, hope it's understandable, I can re-phrase if necessary]
You could use the Factory Pattern to create a UI widget for the element that you are selecting. You could also use it to create a validation rule object depending on the type. This would give you some of the flexibility you desire.
So you can have something like:
IWidget widget = UIFactory.createFor(myObject.getType())
That can be invoked on the selection event to create the right widget to edit the selected element.
The IWidget could have methods such as:
validateData()
refreshData()
setDataElement(IDataElement element)
That would allow you to treat all UI widgets generically, but still have a special UI widget for each element type. I am assuming that the elements that you are selecting from the table all implement some IDataElement interface that contains the getType() method.
I used this solution tied together with the Eclipse Extension mechanism to plug-in new UI elements into my "base" solution, to have an extensible core and a high level of reuse. You could achieve something similar by injecting types and widgets into your factory, either manually or with Spring.
If you dont want to go down the generic path, you could have your model hold a mapping of combobox item -> panel name for use with a CardLayout. You could then create custom panels for the editing each of the reference data types. When the combo box selection is changed, you can save the current state in your model, request the panel name of the current selection, prepare your next panel for display and then have your CardLayout show it.

Categories