How To Display Objects in Java JList? - java

I'm trying to create a student registration system. In this system, students can see course name, course credit, and the instructor of the course by clicking the "Courses" button.For this purpose i have a Courses class, a database, a frame and a JList courslist.
ArrayList<Courses> aq = Database.allCourses();
//allCourses() is a static method in my Database class that returns fields from my Database as an ArrayList<Courses>
courselist.setListData(Driver.converToCoursesArray(aq));
//Driver.converttoCoursesArray() is a static method in my Driver class that takes a ArrayList<Courses> as a paramater and returns a Courses[] array.
Now, my problem is that in my frame, JList always seen like p1.Courses#4532
I've seen a similar problem when i was accidently trying to print an object with System.out.println(). But in this situation i convert the arraylist to an array and my JList holds objects(JList). So i'll be happy if you help me.

You need to override toString() in the Course class, such that it returns the name of the course you want to display.
Take a look at this example:
import javax.swing.*;
import java.awt.*;
public final class Example extends JFrame {
public Example() {
Course[] courses = {
new Course("Course 1"),
new Course("Course 2"),
new Course("Course 3")
};
JList<Course> courseJList = new JList<>(courses);
getContentPane().add(courseJList);
pack();
setMinimumSize(new Dimension(200, 200));
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
final class Course {
private final String courseName;
public Course(final String courseName) {
this.courseName = courseName;
}
#Override
public String toString() {
return courseName;
}
}
This displays the following:

Related

JavaFX Combobox show attribute of element

I am currently working on a game with Java and JavaFX. I am using a JavaFX ComboBox.
The following example should explain my problem.
Let's say I have a class "Animal" with the attributes "name", "age" and "color".
First file:
public class Animal {
private String name;
private int age;
private String color;
public Animal(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
}
Now I want to create a ComboBox with each animal I create.
Second file:
ComboBox<Animal> comboBoxAnimal = new ComboBox();
ObservableList<Animal> comboBoxItems = FXCollections.observableArrayList();
Animal dog = new Animal("Liam", 2, "Brown");
Animal cat = new Animal("Emily", 5, "Gray");
Animal bird = new Animal("Kian", 3, "Green");
comboBoxItems.addAll(dog, cat, bird);
comboBoxAnimal.setItems(comboBoxItems);
Currently I get only "Animal#xxxxxxxx" which is understandable because I have a ComboBox of Animals but want only the names (Strings) to be presented.
Just simply creating a ComboBox<String> won't solve the problem as I need a Combobox<Animal>.
How can I get a Combobox<Animal> but as elements show only the names of each Animal?
Thanks for your feedback :)
Two options:
Use a cell factory.
Use a string converter.
The cell factory and string converter examples used in this answer produce the identical output:
Cell Factory Implementation
Use a cell factory, like in this answer:
How can I Populate a ListView in JavaFX using Custom Objects?
The linked answer is for a ListView, but the ComboBox is similar, as is a TableView or other virtualized controls that rely on cell factories for display.
To configure cells for the ComboBox drop-down list and button, make calls to both setCellFactory and setButtonCell.
This is the most flexible solution and allows for customization beyond just strings of text. Graphic nodes can be created to completely customize the visual representation of each combo box cell.
Example Code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.stage.Stage;
public class AnimalComboApp extends Application {
public record Animal(String name, int age, String color) {}
public static class AnimalCell extends ListCell<Animal> {
#Override
public void updateItem(Animal animal, boolean empty) {
super.updateItem(animal, empty);
if (animal == null || empty) {
setText(null);
} else {
setText(animal.name());
}
}
}
#Override
public void start(Stage stage) throws Exception {
ComboBox<Animal> comboBox = new ComboBox<>();
comboBox.getItems().setAll(
new Animal("Liam", 2, "Brown"),
new Animal("Emily", 5, "Gray"),
new Animal("Kian", 3, "Green")
);
comboBox.setCellFactory(listView -> new AnimalCell());
comboBox.setButtonCell(new AnimalCell());
comboBox.getSelectionModel().select(0);
stage.setScene(new Scene(comboBox));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
StringConverter Implementation
An alternative to a cell factory definition is to provide the ComboBox with a StringConverter which can convert to and from a String and an object.
The StringConverter requires fromString and toString to be implemented, but the fromString implementation can just return null unless you also want the user to be able to perform text edits to edit the combo box value.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class AnimalComboApp extends Application {
public record Animal(String name, int age, String color) {}
#Override
public void start(Stage stage) throws Exception {
ComboBox<Animal> comboBox = new ComboBox<>();
comboBox.getItems().setAll(
new Animal("Liam", 2, "Brown"),
new Animal("Emily", 5, "Gray"),
new Animal("Kian", 3, "Green")
);
comboBox.setConverter(new StringConverter<>() {
#Override
public String toString(Animal animal) {
return animal.name();
}
#Override
public Animal fromString(String string) {
return null;
}
});
comboBox.getSelectionModel().select(0);
Scene scene = new Scene(comboBox);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Options NOT to use
toString() implementation
Do not override toString() to customize the cells, that is an anti-pattern.
Use toString() for other purposes such as listing and debugging all the elements of the Animal class, and instead, use the appropriate methods, such as cell factories or string converters, for customizing the UI view of the Animal.
Placing nodes in the combo box list
You might also be tempted to try to put nodes directly in the ComboBox list (for example create Labels with the name of an object in each Label and then create a ComboBox<Label>).
Don't do this, as advised by the ComboBox API documentation section: "A warning about inserting Nodes into the ComboBox items list", it will create bugs in your application.

non-static JLabel cannot be referenced from static context while moving console println into GUI

Whatever I try to modify there's always a problem and the program won't run.
The thing is that my program works fine, when it's launched in the console, everything is ok, but when I try to make a GUI, and get text from console in the window, variables doesn't seem to work as they were.
The program is very simple, it has three packages like this:
//class SklepZoologiczny in package sklepzoologiczny
package sklepzoologiczny;
import javax.swing.JFrame;
import zwierzeta.*;
import magazyn.*;
public class SklepZoologiczny {
public static void main(String[] args) {
GUI GUI = new GUI();
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.pack();
GUI.setSize(300, 500);
GUI.setVisible(true);
GUI.setTitle("Appka Zaliczeniowa - Sklep Zoologiczny");
GUI.setResizable(false);
GUI.setLocationRelativeTo(null);
}
}
//class GUI in package sklepzoologiczny
package sklepzoologiczny;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import magazyn.*;
import zwierzeta.*;
public class GUI extends JFrame {
public JLabel l_imie, l_gatunek, l_rasa;
public JButton b_dodaj, b_usun, b_lista;
public JTextField tf_imie, tf_gatunek, tf_rasa;
public String imie, gatunek, rasa;
public ArrayList lista_psow, lista_kotow;
public String pies, kot, gatunek_zwierza;
public String imie_psa, rasa_psa;
public String imie_kota, rasa_kota;
public GUI() {
setLayout(new FlowLayout());
b_dodaj = new JButton("Uruchom Program");
add(b_dodaj);
l_imie = new JLabel("Text from console to GUI should go here");
add(l_imie);
event dodanie = new event();
b_dodaj.addActionListener(dodanie);
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent dodanie) {
magazyn magazyn1 = new magazyn();
magazyn1.kasa = 0;
pies pies1 = new pies();
kot kot1 = new kot();
krolik krolik1 = new krolik();
pies1.ustawImie("Max");
kot1.ustawImie("Nuta");
krolik1.ustawImie("Filip");
pies1.ustawCene(200);
kot1.ustawCene(100);
krolik1.ustawCene(50);
pies1.ustawRase("Jamnik");
kot1.ustawRase("Perski");
krolik1.ustawRase("Mini_Lop");
pies1.ustawGatunek("pies");
kot1.ustawGatunek("kot");
krolik1.ustawGatunek("krolik");
System.out.println("Operacje Zakupu Zwierzat");
System.out.println("---");
magazyn1.dodajZwierza(pies1);
magazyn1.dodajZwierza(kot1);
magazyn1.dodajZwierza(krolik1);
magazyn1.StanSklepu();
System.out.println("Transkacje");
System.out.println("---");
magazyn1.sprzedajZwierza("Nuta");
magazyn1.StanSklepu();
}
}
}
//class magazyn in package magazyn
package magazyn;
import java.util.ArrayList;
import zwierzeta.*;
public class magazyn {
public float kasa;
ArrayList <zwierzeta> lista = new ArrayList(20);
public void dodajZwierza(zwierzeta i){
lista.add(i);
sklepzoologiczny.GUI.l_rasa.setText("Do sklepu dodano zwierza o imieniu: " + i.wezImie());
}
public void sprzedajZwierza(String i){
for(int j=0; j<lista.size(); j++){
if(lista.get(j).wezImie() == i){
kasa = kasa + lista.get(j).wezCene();
lista.remove(j);
System.out.println("Sprzedano: " + i);
}
}
}
public void StanSklepu(){
System.out.println("Aktualny stan sklepu:");
for(int i=0; i<lista.size(); i++){
System.out.println(lista.get(i).wezImie()+", " +lista.get(i).wezGatunek()+", " + lista.get(i).wezRase() + ", cena: " + lista.get(i).wezCene());
}
System.out.println("Stan kasy \t\t\t" + kasa);
}
}
//class zwierzeta in package zwierzeta
package zwierzeta;
public abstract class zwierzeta {
String imie, gatunek, rasa;
float cena;
/* public void checkProduct() throws ProductException{
if(isDamaged == true){
ProductException damaged = new ProductException();
damaged.setErrorMessage("Product is damaged:");
throw damaged;
}
}*/
public void ustawImie(String i){
imie = i;
}
public String wezImie(){
return imie;
}
public void ustawGatunek(String i){
gatunek = i;
}
public String wezGatunek(){
return gatunek;
}
public void ustawRase(String i){
rasa = i;
}
public String wezRase(){
return rasa;
}
public void ustawCene(float i){
cena = i;
}
public float wezCene(){
return cena;
}
}
There are also three classes in package zwierzeta which only extends zwierzeta with no code in it.
So the thing is, whatever I try to put in the dodajZwierza in magazyn.java, there's always an error which says that I can't use non-static variable l_rasa to reference in a static context. I don't know how to fix this, I tried to make class as static in GUI but it just gets worse with more errors.
How can I get the text to appear in the window instead of a console?
First of all - you better avoid using members with names identical to type names:
GUI GUI = new GUI();
You - and the JVM - are more than likely to get confused by this, not knowing whether you are trying to access the class type or the class instance when you later run something like:
GUI.setVisible(true);
Second, if you want to let one class access a member of another class, it is much better to provide a getter that returns (a reference to ) that member, instead of defining the member as static and let the other classes access it directly.
You seem to conflate classes and instances: you want to create an instance of class GUI and then pass this instance around to be able to use the instance rather than the class.
In your main method, you create an instance of class GUI:
GUI GUI = new GUI();
The variable which refers to this instance you call GUI, the same as the class. This is a very bad idea. Java naming conventions dictate that variable names start with a non-capital letter, so you should write:
GUI gui = new GUI();
and change the rest of the main method accordingly.
Now, this instance gui is what you want to use. You have to pass it to the methods where you use it, and then write for example
gui.l_rasa.setText(...);
By the way, your code becomes more maintainable if you make the member variables of a class private, and add getter and setter methods to access them.
You are trying to access non static variable defined in GUI class as:
public JLabel l_imie, l_gatunek, l_rasa;
Here:
sklepzoologiczny.GUI.l_rasa.setText
I dont see its being initialised, but you could define it as static in GUI class like:
public static JLabel l_rasa;//initialize it may be and that would resolve your issue.

Problems with JComboBox

import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class Test1{
JComboBox combo;
JTextField txt;
public static void main(String[] args) {
Test1 b = new Test1();
}
public Test1(){
String degrees[] = {"AAS1","AAS2","AAS1","AAS3"};
JFrame frame = new JFrame("Creating a JComboBox Component");
JPanel panel = new JPanel();
combo = new JComboBox(degrees);
combo.setEditable(true);
combo.setBackground(Color.gray);
combo.setForeground(Color.red);
txt = new JTextField(10);
txt.setText("1");
panel.add(combo);
panel.add(txt);
frame.add(panel);
combo.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent ie){
txt.setText(String.valueOf(combo.getSelectedIndex()+1));
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
} }
As you see from the code above. I have JComboBox with 4 items. If there are no items that are same everything is OK.
But in my example ("AAS1","AAS2","AAS1","AAS3") first and third items are same, and I have problems in this case.
When I select any item I want to get it's index in JTextField, but when I select third item I get index of first item.
Has any idea?
That's because JComboBox is using equals to check the item equality. In your case, those two String are equal so it returns the first index that match. If you really need to do that, you might need to define your own item class like this:
private static class MyItem {
private String value;
public MyItem(String value) {
this.value = value;
}
public String getValue() {
return value;
}
#Override
public String toString() {
return value; //this is what display in the JComboBox
}
}
And then add the item like this:
MyItem degrees[] = {new MyItem("AAS1"),new MyItem("AAS2"),new MyItem("AAS1"),new MyItem("AAS3")};
JComboBox combo = new JComboBox(degrees);
Create a class like that:
class ComboItem{
private String name;
public ComboItem(String name){
this.name = name;
}
public String toString() {
return name;
}
}
and create your combobox:
comboBox = new JComboBox(new ComboItem[]{
new ComboItem("AAS1"),
new ComboItem("AAS2"),
new ComboItem("AAS1"),
new ComboItem("AAS3")
});
You have to separate how the equals is calculated on the Strings items and the effective representation. I think that this can be done just by creating a specific class for your purpose and use it instead that String.
Since this could be homework I'm not going to give exact result, just think about how the JComboBox internally chooses the index specified.
try using combo.getSelectedItem() instead. Since its two different strings in the String Array, you should be able to do a reference comparison and tell a difference between the two.

Java - Displaying contents of a HashMap using (Abstract)ListModel

I am designing a basic telephone directory for a project. It has three classes, Main (for the GUI), TelephoneDirectory (an object to store TelephoneRecords objects) and a TelephoneRecords class (where information for each record object is stored).
The requirements state: Extend your application by adding a list displaying the complete current contents of the telephone directory, ordered alphabetically by name. You will need to implement a ListModel. You may want to study class AbstractListModel before starting on your own implementation.
Only problem is, I have absolutely no idea how to extend my application to achieve this. I have searched online all night and haven't found a way to do this. I have tried storing the objects in an AbstractListModel rather than a HashMap but get errors. I don't exactly know what or why it is used and how I could use it. The next requirement (by the way) is to have the JList auto-update with new data when it's entered so I guess it has something to do with that?
Either way, if anyone could help it'd be great. My current working code for the previous that needs to be edited version is:
MAIN
public class Main extends JFrame implements ActionListener {
private static TelephoneDirectory directory = new TelephoneDirectory();
private JTextField nameField;
private JTextField numberField;
private JList contactList;
public Main() {
setTitle("Telephone Directory");
setLayout(new GridLayout(0,2));
JLabel nameLabel = new JLabel("Name of Contact:");
nameField = new JTextField(20);
add(nameLabel);
add(nameField);
JLabel numberLabel = new JLabel("Number of Contact:");
numberField = new JTextField(20);
add(numberLabel);
add(numberField);
JButton enterButton = new JButton("Enter");
JButton cancelButton = new JButton("Cancel");
enterButton.addActionListener(this);
cancelButton.addActionListener(this);
add(enterButton);
add(cancelButton);
JLabel contactsLabel = new JLabel("Current Contacts:");
contactList = new JList();
add(contactsLabel);
add(contactList);
setVisible(true);
pack();
}
public static void main(String[] args) {
new Main();
}
#Override
public void actionPerformed(ActionEvent arg0) {
JButton jb = (JButton) arg0.getSource();
if (jb.getText().equals("Cancel")) {
System.exit(0);
} else {
directory.addRecord(nameField.getText(), new TelephoneRecords(nameField.getText(), numberField.getText()));
System.out.println("Added record for " + nameField.getText() + ": number is " + numberField.getText() + ".");
}
}
}
TELEPHONEDIRECTORY
public class TelephoneDirectory implements Iterable<TelephoneRecords> {
private HashMap records;
public TelephoneDirectory() {
records = new HashMap<String, TelephoneRecords>();
}
public void addRecord(String name, TelephoneRecords newRecord) {
records.put(name, newRecord);
}
public TelephoneRecords getRecord(String name) {
return (TelephoneRecords) records.get(name);
}
public void getDirectory() {
System.out.println("Telephone Directory:");
records.values().iterator();
}
#Override
public Iterator<TelephoneRecords> iterator() {
return records.values().iterator();
}
}
TELEPHONERECORDS
public class TelephoneRecords {
private String name;
private String number;
public TelephoneRecords(String name, String number) {
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public String getNumber() {
return number;
}
#Override
public String toString() {
return "The phone number of " + name + " is " + number + ".";
}
}
You may be trying to do too much with inheritance. Rather than using an AbstractListModel in place of your HashMap, consider creating a class that extends AbstractListModel and that holds the TelephoneDirectory class with its HashMap as the nucleus of the AbstractListModel's data. This is called extending a class by composition rather than by inheritance.
Edit: Also consider using a TreeMap rather than a HashMap so as to be able to retrieve your names and telephone records in name order. You'll also need to give your TelephoneDirectory class a getElementAt(int index) and a getSize() method to allow it to be used within the AbstractListModel class.

Have com.l2fprod.common.propertysheet.PropertySheetPanel To Display Composited Class

In order to have a Netbeans liked property inspector windows, I am making use of the following class to help me achieve this.
com.l2fprod.common.propertysheet.PropertySheetPanel
So far, it works fine for class with simple properties like String, int...
However, when come to slightly complicated class with composited relationship, things get more complicated.
For example, I have two animals (interface). One is Cat (Simple class with name and age) and Dog (Another simple class with name and age).
It takes no effort to display them through GUI windows.
However, when come to class with composited relationship. A Zoo, which can contains multiple animals (A class with array list to hold animals), I have problem to display all the animals properties within a single window.
The following is the screen shoot
(source: googlepages.com)
Partial source code is shown here
ObjectInspectorJFrame objectInspectorJFrame0 = new ObjectInspectorJFrame(cat);
objectInspectorJFrame0.setVisible(true);
objectInspectorJFrame0.setState(java.awt.Frame.NORMAL);
ObjectInspectorJFrame objectInspectorJFrame1 = new ObjectInspectorJFrame(dog);
objectInspectorJFrame1.setVisible(true);
objectInspectorJFrame1.setState(java.awt.Frame.NORMAL);
// I wish to see all "animals" and their properties in this windows. :(
// How?
ObjectInspectorJFrame objectInspectorJFrame2 = new ObjectInspectorJFrame(zoo);
objectInspectorJFrame2.setVisible(true);
objectInspectorJFrame2.setState(java.awt.Frame.NORMAL);
Complete source code can be downloaded from
http://yancheng.cheok.googlepages.com/sandbox.zip
I wish within "Zoo" windows, it can display all the properties for all animals.
PropertySheetPanel as is only populates its table reading the properties for a given Java Bean.
You need to extend PropertySheetPanel behaviour and populate the properties from a given Collection. Iterate your collection and use addProperty(Property) to populate the table.
You can also use instrospection or beanutils lib to discover the collection elements.
EDIT: Example added.
package com.stackoverflow.swing.PropertySheetPanel;
import java.util.ArrayList;
import java.util.Collection;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.l2fprod.common.propertysheet.DefaultProperty;
import com.l2fprod.common.propertysheet.PropertySheetPanel;
/**
* An example that creates a l2fprod PropertySheetPanel that displays any
* Collection.
*/
public class CollectionPropertySheet<C> extends PropertySheetPanel {
// Choose some bean. An animal as example.
static class Animal {
private String name;
private String family;
public Animal(String name, String family) {
this.name = name;
this.family = family;
}
#Override public String toString() {
return name + " " + family;
}
}
/**
* #param simpleModel The input collection as data model.
*/
public CollectionPropertySheet(Collection<C> simpleModel) {
super();
populateCollectionProperties(simpleModel);
}
private void populateCollectionProperties(Collection<C> collection) {
int index = 0;
for (C entry : collection) {
// Define property properties
DefaultProperty property = new DefaultProperty();
property.setDisplayName(entry.getClass().getSimpleName() + "[" + index++ +"]");
property.setValue(entry.toString());
// Set any other properties ...
// and add.
addProperty(property);
}
}
// Start me here!
public static void main(String[] args) {
// Inside EDT
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
JFrame frame = new JFrame("A simple example...");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CollectionPropertySheet<Animal>(getAnimals()));
frame.pack();
frame.setVisible(true);
}
private Collection<Animal> getAnimals() {
Collection<Animal> animals = new ArrayList<Animal>();
animals.add(new Animal("Lion", "Felidae"));
animals.add(new Animal("Duck", "Anatidae"));
animals.add(new Animal("Cat", "Felidae"));
return animals;
}
});
}
}

Categories