I am trying to generate a jList of classes.
If I do:
package test;
import javax.swing.DefaultListModel;
public class TestFrame extends javax.swing.JFrame {
DefaultListModel jList1Model = new DefaultListModel();
public TestFrame() {
initComponents();
jList1Model.addElement(TestClass.class);
jList1.setModel(jList1Model);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jList1 = new javax.swing.JList<>();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jList1.setModel(new javax.swing.AbstractListModel<String>() {
String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
public int getSize() { return strings.length; }
public String getElementAt(int i) { return strings[i]; }
});
jScrollPane1.setViewportView(jList1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
.addContainerGap())
);
pack();
}// </editor-fold>
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JList<String> jList1;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
Being my TestClass
:
package test;
public class TestClass {
public static String name = "Test Class 1";
public int foo;
public int bar;
}
Then I get:
So far, so good.
Now I would like to have the content of the name
class attribute instead of class test.TestClass
displayed in the jList1.
I have tried this:
public class TestClass {
public static String name = "Test Class 1";
public int foo;
public int bar;
public static String toString() {
return name;
}
}
But I can not even compile it as I get:
toString() in TestClass cannot override toString() in Object overriding mehtod is static.
Not an answer to overriding the toString
method but a solution of how to have a list displaying something different than what is returned by toString
. Add a ListCellRenderer
to the list. Basically extend the default one (an extension of JLabel
itself) and change what should be displayed:
class ClassRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(
JList<?> list, Object value, int index, boolean selected, boolean focus) {
if (value instanceof Class) {
value = ((Class<?>) value).getSimpleName();
}
return super.getListCellRendererComponent(list, value, index, selected, focus);
}
}
To use it just call (before displaying the list)
list.setCellrenderer(new ClassRenderer());
More details, better explanation can be found in official tutorial: Providing a Custom Renderer
Solution suggested by JB Nizet (my interpretation, hope I did understand it correctly): create an object to hold the Class
and its label; add its instance to the list:
public class LabeledClass {
private final String label;
private final Class<?> theClass;
LabeledClass(String label, Class<?> theClass) {
this.label = Objects.requireNonNull(label);
this.theClass = theClass; // TODO null check?
}
public Class<?> getTheClass() {
return theClass;
}
@Override
public String toString() {
return label;
}
// TOD hashcode, equals ?
}
used as:
model.addElement(new LabeledClass("Test", TestClass.class));
No need to change the default cell renderer for this. Advantage: is is more OO if changed to be used in your chart, very simple example, instead of LabeledClass
:
public abstract class ChartEnricher {
private final String name;
protected ChartEnricher(String name) {
this.name = Objects.requireNonNull(name);
}
public abstract void enrichChart();
@Override
public String toString() {
return name;
}
}
The enrichChart
method must be implement for each possible entry, or have a generic one that uses a Class
given to its constructor (as LabeledClass
). Obviously this can be extended if required for more functionality depending on use case.
Just in case it helps someone, using inputs to original OP I finally combined accepted answer with a static method named getClassName
which is invoked via reflection.
Note: I have included the final code which uses slightly different names but still shows reflection usage. My real app is obviously a bit more complex than the included simplified OP posted example as it is intended to use many classes extended from an abstract class that enforces the extended classes to implement several methods.
As a side note: the only thing I have not managed to enforce is the implementation of the static getClassName
method, as apparently you can not enforce static methods implementation in Java (apparently abstract static methods are not possible).
class IndicatorsRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Class<? extends BaseIndicator> baseIndicatorClass = ((Class<? extends BaseIndicator>) value);
try {
return super.getListCellRendererComponent(list, baseIndicatorClass.getMethod("getClassName").invoke(baseIndicatorClass), index, isSelected, cellHasFocus);
} catch (NoSuchMethodException ex) {
Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "No such method exception while trying to access Name of indicator. Exception {0}", ex);
System.exit(1);
} catch (SecurityException ex) {
Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Security exception while trying to access Name of indicador. Exception {0}", ex);
System.exit(1);
} catch (IllegalAccessException ex) {
Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Illegal Access Exception while trying to access Name of indicator. Exception {0}", ex);
System.exit(1);
} catch (IllegalArgumentException ex) {
Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Illegal Argument Exception while trying to access Name of indicator. Exception {0}", ex);
System.exit(1);
} catch (InvocationTargetException ex) {
Logger.getLogger(IndicatorsRenderer.class.getName()).log(Level.SEVERE, "Invocation Target Exception while trying to access Name of indicator. Exception {0}", ex);
System.exit(1);
}
return null;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.