what's up?
I created one jList on my project that I can't retrieve the element. I know jList only accepts objects, but I was adding Strings to my list, because when I add "Discipline" object, I see something like "Discipline{id=21, name=DisciplineName}" on my view. So, I'm adding strings instead objects.
Following is my code:
ArrayList<Discipline> query = myController.select();
for (Discipline temp : query){
model.addElement(temp.getNome());
}
When I get the index of a double click in one element, I try to retrieve my String to make a query and know what's this discipline. But I'm getting some errors, see what I already tried:
Object discipline = lista1.get(index);
// Error: local variable lista1 is accessed from within inner class; needs to be declared final
String nameDiscipline = (String) lista1.get(index);
// Error: local variable lista1 is accessed from within inner class; needs to be declared final
I really don't know what means "final", but what can I do to solve this problem? One thing that I thinked is:
Can I add a Discipline instead String, show to user discipline.getName() and retrieve Discipline object?
Yes, add Discipline objects. A quick fix is to change Discipline's toString method, but a much better fix is to create a ListCellRenderer that displays each Discipline's data in a nice String.
Here are two ListCellRenderers that I have used in a project of mine to change the item displayed in my JList from text to an ImageIcon:
private class ImgListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (value != null) {
BufferedImage img = ((SimpleTnWrapper) value).getTnImage();
value = new ImageIcon(img); // *** change value parameter to an ImageIcon
}
return super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
}
}
private class NonImgCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
// all this does is use the item held by the list, here value
// to extract a String that I want to display
if (value != null) {
SimpleTnWrapper simpleTn = (SimpleTnWrapper) value;
String displayString = simpleTn.getImgHref().getImgHref();
displayString = displayString.substring(displayString.lastIndexOf("/") + 1);
value = displayString; // change the value parameter to the String ******
}
return super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
}
}
They are declared like so:
private ListCellRenderer imgRenderer = new ImgListCellRenderer();
private ListCellRenderer nonImgRenderer = new NonImgCellRenderer();
And I use them thusly:
imgList.setCellRenderer(imgRenderer);
The DefaultListCellRenderer is pretty powerful and knows how to display a String or an ImageIcon correctly (since it is based off of a JLabel).
Related
I have a JComboBox that I made this way, using an enum for its values:
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
The enum looks like this:
public enum StudyGrade {
ELEMENTARY ("Primaria"),
MIDDLE ("Secundaria"),
MIDDLE_HIGH ("Preparatoria"),
HIGH ("Universidad"),
MASTERS ("MaestrÃa / Posgrado"),
DOCTORATE ("Doctorado"),
POST_DOCTORATE ("Post Doctorado");
private String studies;
private StudyGrade(String studies) {
this.studies = studies;
}
public String getStudies() {
return studies;
}
public void setStudies(String studies) {
this.studies = studies;
}
#Override
public String toString() {
return studies;
}
}
As you can see I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
However I want to show the studies values only in the JComboBox not everytime I use the StudyGrade enum.
How would I change the code, so whenever I use something like:
System.out.println(StudyGrade.HIGH);
I get printed HIGH instead of Universidad, but not for the JComboBox?
I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
I've never used a enum before but I assume you can use it like any custom object added to the combo box so you should be able to use a custom renderer so you can control which data is displayed by the combo box.
Check out Combo Box With Custom Renderer for more information and a helper class.
You're looking to extend an enum, but that's impossible. It means that something is wrong with your requirement.
Rendering is done in the UI component, and it's not enum's business to deal with presentation of data. You should make you UI component render enum the way you'd like instead of trying to make enum understand where it's being used. Since you're a Swing fanatic you should know how to do that, something like this:
maxLevelOfStudiesCombo.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> jList, Object o, int i, boolean b, boolean b1) {
Component rendererComponent = super.getListCellRendererComponent(jList, o, i, b, b1);
setText(o instanceof StudyGrade ? ((StudyGrade) o).getStudies() : o.toString());
return rendererComponent;
}
});
That's going to do that.
You could just remove the toString override as the default toString for an enum is to return the name of the enum element.
And you could just have a simple for loop that would iterate through the values in your enums and add it to a string array. Then, you would need to pass that array as the argument for your JComboBox and it should be gold.
The code for it should look a bit like that:
//get all study grades
StudyGrade[] temp = StudyGrade.values();
//create a string array of same length as the array
String[] str = new String[temp.length];
//append all the studies value to the string array
for(int i = 0; i< temp.length; i++){
str[i] = temp[i].getStudies();
System.out.println(temp[i]);//debug
}
System.out.println("---------------------");//debug
for(String s : str){//debug
System.out.println(s);//debug
}//debug
//pass it
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
Here is an example I made on repl.it
https://repl.it/GH28/1
I hope I will get help, I will ask as general question:
I am using a JList, and due to the JList not have a (value,text) (so I can display text and use the value in my code). Because of this leak I create List of object (myList), that work parallel with the JList. Every item I add to JList I add to myList, so the same index will contain the same info in the two objects (JList and mylist)
I use the JList.getselectedindex() method to get the index and use it in myList to pup information...
The problem: is when I select value, the next value of the myList is overridden with the first value!!!
Is this problem known?
mod_mp = new ModelMAPPING(); objects cotain values that ot exist in jList
msgF.setTo(incom.userID);/////// set parter!
if(isExCon==-1) {
// not exist
mod_mp.to = incom.userID; // incom is object that incom from another program
mod_mp.SetCovFile(incom.userID+".html");
mod_mp.ConvName = incom.getBody();
boolean added= model_list.add(mod_mp); // add to mylist
if(added) System.out.println(mod_mp._Hfile + " added");
model.addElement(mod_mp.ConvName);// add to Jlist by model
HestoryFile(Htmlhead+tohis,mod_mp._Hfile);//create _Hfile and write to it:"tohis" string.
} else { //exist#
// note isExcon return the index if exist else -1
model_list.get(isExCon).ConvName=incom.getBody();
mod_mp.SetCovFile(model_list.get(isExCon)._Hfile);
HestoryFile(tohis, model_list.get(isExCon)._Hfile);
}//end else
Here if file exists I just update the new text in the JList and set the current file
The select of JList is:
msgF.setTo (model_list.get(jList2.getSelectedIndex()).to); // set that we will send To...
mod_mp.SetCovFile(model_list.get(jList2.getSelectedIndex())._Hfile);//set the file
jLabel5.setText( bringFromFile(mod_mp._Hfile));//tell the label to read that file
It works fine, but when I have two items in JList if I select any, the other is overridden!!!
I am using a JList, and due to the JList not have a (value,text) (so I
can display text and use the value in my code)
It's really hard to understand your problem, but I "suspect" for the quoted line that you have a missunderstanding between JList model and text displayed by the JList itself. I think that's why you have a separate List.
The model can contain any object you want and the JList can also display a text as you want regardless the object itself. This last task is done by a ListCellRenderer. Take a look to Writing a Custom Cell Renderer
For instance you can have this class:
class Person {
String lastName;
String name;
public Person(String lastName, String name){
this.lastName = lastName;
this.name = name;
}
public String getLastName(){
return this.lastName;
}
public String getName(){
return this.name;
}
}
Now you want your JList keep Person objects to work with them later. This part is easy just create a ListModel and add elements into it:
DefaultListModel model = new DefaultListModel();
model.addElement(new Person("Lennon","John"));
model.addElement(new Person("Harrison","George"));
model.addElement(new Person("McCartney","Paul"));
model.addElement(new Person("Starr","Ringo"));
But you want to display the name and last name of each Person. Well you can implement your own ListCellRenderer to do this:
JList list = new JList(model);
list.setCellRenderer(new DefaultListCellRenderer(){
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if(value instanceof Person){
Person person = (Person)value;
setText(person.getName() + " " + person.getLastName());
}
return this;
}
});
And your JList will show the items as you want:
A quick question about the example code in the JavaDoc for javax.swing.ListCellRenderer:
I'm a little surprised, that in the example, the ListCellRenderer is implemented by a class that extends JLabel and that the getListCellRendererComponent(...)-method simply returns this. It looks like there is only one instance of a JLabel around then, even for a list containing more than one element.
Usually, I would then expect that when the setText(...) method is called inside getListCellRendererComponent(...) for the second item in the list, it changes the label of the already existing first item in the list. Or, actually, it probably shouldn't even be possible for the list to use the same JLabel-instance twice (or more times), once for each item in the list.
Now, I've come up with two possible ways to resolve this and was wondering which one (if any) is actually happening:
Does JList somehow create new instances of the provided ListCellRenderer for each list item?
Or does it use the component returned by getListCellRendererComponent(...) only to invoke its paint(...) method on the list's canvas rather than actually adding this component to some panel?
When the JList renders itself it asks the ListModel for the elements it should display.
For each element it calls the javax.swing.ListCellRenderer to provide a render component. Then it paints the component. That's all. A render component is not bound to an element's state that it renders.
The javadoc of ListCellRenderer says:
Identifies components that can be used as "rubber stamps"
to paint the cells in a JList.
So your second assumption is right.
A look at javax.swing.plaf.BasicListUI shows it:
protected void paintCell(Graphics g, int row, Rectangle rowBounds,
ListCellRenderer cellRenderer, ListModel dataModel,
ListSelectionModel selModel, int leadIndex) {
Object value = dataModel.getElementAt(row);
boolean cellHasFocus = list.hasFocus() && (row == leadIndex);
boolean isSelected = selModel.isSelectedIndex(row);
Component rendererComponent = cellRenderer
.getListCellRendererComponent(list, value, row, isSelected,
cellHasFocus);
int cx = rowBounds.x;
int cy = rowBounds.y;
int cw = rowBounds.width;
int ch = rowBounds.height;
if (isFileList) {
// Shrink renderer to preferred size. This is mostly used on Windows
// where selection is only shown around the file name, instead of
// across the whole list cell.
int w = Math
.min(cw, rendererComponent.getPreferredSize().width + 4);
if (!isLeftToRight) {
cx += (cw - w);
}
cw = w;
}
rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch,
true);
}
I have a list of expences that looks like this :
My List
I would like the elements of the list to appear as if formatted with \t :
PRODUCT NAME PRICE DATE
PRODUCT NAME PRICE DATE
ect. I created DefaultListCellRenderer but I don't know how to implement this formatting.. If it's not doable, than at least how do I center the elements?
My DefaultListCellRenderer looks like this at the moment :
private class MyListRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent( JList<?> list,
Object value, int index, boolean isSelected,
boolean cellHasFocus )
{
Component c = super.getListCellRendererComponent( list, value, index,
isSelected, cellHasFocus );
Color czerwony = new Color(205, 16, 26);
setForeground(czerwony);
return(this);
}
}
Shoot, I'll make my comment an answer: use a JTable to display tabular data since it excels at this and was built for this. Otherwise if you want to create your own kludge of a Table via a JList, you'll be forced to use mono-spaced fonts and code that can easily break if one item of data exceeds the expected width of that column.
If you have restrictions on why you can't or are not allowed to use this, then please by all means share this with us.
I have a table where each row represents a picture. In the column Path I store its absolute path. The string being kinda long, I would like that when I hover the mouse over the specific cell, a tooltip should pop-up next to the mouse containing the information from the cell.
Just use below code while creation of JTable object.
JTable auditTable = new JTable(){
//Implement table cell tool tips.
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p);
int colIndex = columnAtPoint(p);
try {
tip = getValueAt(rowIndex, colIndex).toString();
} catch (RuntimeException e1) {
//catch null pointer exception if mouse is over an empty line
}
return tip;
}
};
I assume you didn't write a custom CellRenderer for the path but just use the DefaultTableCellRenderer. You should subclass the DefaultTableCellRenderer and set the tooltip in the getTableCellRendererComponent. Then set the renderer for the column.
class PathCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(
JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
JLabel c = (JLabel)super.getTableCellRendererComponent( /* params from above (table, value, isSelected, hasFocus, row, column) */ );
// This...
String pathValue = <getYourPathValue>; // Could be value.toString()
c.setToolTipText(pathValue);
// ...OR this probably works in your case:
c.setToolTipText(c.getText());
return c;
}
}
...
pathColumn.setCellRenderer(new PathCellRenderer()); // If your path is of specific class (e.g. java.io.File) you could set the renderer for that type
...
Oracle JTable tutorial on tooltips
You say you store an absolute path in a cell. You are probably using a JLabel for setting absolute path string. Suppose you have a label in your cell, use html tags for expressing tooltip content:
JLabel label = new JLabel("Bla bla");
label.setToolTipText("<html><p>information about cell</p></html>");
setToolTipText() can be used for some other Swing components if you are using something other than JLabel.