Reputation: 1
As an assignment, I am required to make a Swing GUI. In the first part, I have created an ArrayList
(f1Driver
) of objects (Formula1Driver
). At the moment what is required is to sort said array list and display it as a JTable
in the GUI. There is a JButton
I have made and when it is pressed it is supposed to sort and display.
However, once pressed it will only show the table headings and not the information in the array list, what should I do differently? I have included the GUI class and the main class below.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Formula1ChampionshipManager formula1ChampionshipManager =new Formula1ChampionshipManager();
F1ChampionshipGUI guiCode = new F1ChampionshipGUI();
formula1ChampionshipManager.loadPreviousData();
String menu ="";
Scanner input = new Scanner(System.in);
while (true) {
System.out.println("Enter required menu value to continue"+ //Allow user to enter the values and use the program
"\n1 or AND:Add a new driver."+
"\n2 or RMD:Remove a driver."+
"\n3 or CDT:Change driver of a team."+
"\n4 or DDS:Display the statistics of a driver."+
"\n5 or DDT:Display the Formula1 driver table."+
"\n6 or ARD:Add the details of completed race."+
"\n7 or SCD:Save the current data."+
"\n8 or LPD:Load the previous data."+
"\n9 or GUI:Access the user interface."+
"\n0 or EXT:Exit and terminate the program.");
menu = input.nextLine();
if ((menu.equals("1")) || (menu.equalsIgnoreCase("AND"))) { //calls each of the methods.
formula1ChampionshipManager.addDriver();
System.out.println("New driver has been added.");
} else if ((menu.equals("2")) || (menu.equalsIgnoreCase("RMD"))) {
formula1ChampionshipManager.removeDriver();
System.out.println("The driver has been removed.");
} else if ((menu.equals("3")) || (menu.equalsIgnoreCase("CTD"))) {
formula1ChampionshipManager.changeDriver();
System.out.println("The driver of the team has been changed.");
} else if ((menu.equals("4")) || (menu.equalsIgnoreCase("DDS"))) {
formula1ChampionshipManager.displayDriverStats();
System.out.println("The driver's statistics has been displayed.");
} else if ((menu.equals("5")) || (menu.equalsIgnoreCase("DDT"))) {
formula1ChampionshipManager.displayDriverTable();
System.out.println("The Formula1 driver table has been displayed.");
} else if ((menu.equals("6")) || (menu.equalsIgnoreCase("ARD"))) {
formula1ChampionshipManager.addRaceDetails();
System.out.println("The details of the completed race has been added..");
} else if ((menu.equals("7")) || (menu.equalsIgnoreCase("SCD"))) {
formula1ChampionshipManager.saveCurrentData();
System.out.println("All current data has been saved to file.");
} else if ((menu.equals("8")) || (menu.equalsIgnoreCase("LPD"))) {
formula1ChampionshipManager.loadPreviousData();
System.out.println("All previous data has been loaded from file.");
}else if ((menu.equals("9")) || (menu.equalsIgnoreCase("GUI"))) {
guiCode.gui();
System.out.println("The user interface has been opened.");
} else if ((menu.equals("0")) || (menu.equalsIgnoreCase("EXT"))) {
System.out.println("Manager program has been terminated.");
break;
}
}
}
}
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.JTextComponent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Vector;
public class F1ChampionshipGUI extends Formula1ChampionshipManager {
DefaultTableModel tModel;
JTable table;
public void gui() {
JFrame frame = new JFrame("F1 Championship Manager Interface");
JPanel panel1 = new JPanel();
panel1.setBounds(0,0,550,500);
JLabel descendPointTable = new JLabel("Display the drivers in descending order of points:");
descendPointTable.setBounds(50, 50, 400, 30);
JButton ascendBtn = new JButton("Display");
ascendBtn.setBounds(400, 50, 80, 30);
frame.add(descendPointTable);
frame.add(ascendBtn);
frame.setSize(550, 500);
frame.setLayout(null);
frame.setVisible(true);
ascendBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < f1Driver.size() - 1; i++) {
for (int j = 0; j < f1Driver.size() - 1 - i; j++) {
if ((f1Driver.get(j).compareTo(f1Driver.get(j + 1))) < 0) {
Formula1Driver tempDriver = f1Driver.get(j + 1);
f1Driver.set(j + 1, f1Driver.get(j));
f1Driver.set(j, tempDriver);
}
}
}
// JTable table=new JTable();
// table.setModel(new javax.swing.table.DefaultTableModel(new Object[][]{},new String[]{"Name","Team","Location","1st positions","2nd positions","3rd positions","Races participated","Current points"}));
//// addToTable();
//
// public static void addToTable(ArrayList<Formula1Driver> ,JTable table){
JFrame fDescend = new JFrame();
tModel = new DefaultTableModel(0, 0);
table = new JTable(tModel);
fDescend.setSize(1500, 400);
fDescend.setVisible(true);
String[] statFields = {"Name", "Team", "Location", "First positions", "Second positions", "Third positions", "Races participated", "Points"};
// int driversCount = 0;
// for (int a=0;a<f1Driver.size();a++){
// driversCount++;
// }
tModel.setColumnIdentifiers(statFields);
table.setModel(tModel);
table.setBounds(0, 500, 1200, 500);
table.setOpaque(true);
for (int b = 0; b < f1Driver.size(); b++) {
Object[] stats = new Object[]{
f1Driver.get(b).getDriverName(),
f1Driver.get(b).getDriverTeam(),
f1Driver.get(b).getDriverLocation(),
f1Driver.get(b).getFirstPositions(),
f1Driver.get(b).getSecondPositions(),
f1Driver.get(b).getThirdPositions(),
f1Driver.get(b).getRacesParticipated(),
f1Driver.get(b).getPoints(),
};
tModel.addRow(stats);
}
// for(int x=0;x<f1Driver.size();x++) {
// Vector<Object> data = new Vector<Object>();
//
//
// data.addElement(f1Driver.get(x).getDriverName());
// data.addElement(f1Driver.get(x).getDriverTeam());
// data.addElement(f1Driver.get(x).getDriverLocation());
// tModel.addRow(data);
// }
//
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(0, 500, 1200, 500);
panel1.add(scrollPane);
fDescend.add(panel1);
}
});
}
}
Upvotes: 0
Views: 804
Reputation: 347204
The "primary" issues comes about from, I suspect, a data sharing issue.
Basically, F1ChampionshipGUI
extending from Formula1ChampionshipManager
, but you create a separate Formula1ChampionshipManager
instance
Formula1ChampionshipManager formula1ChampionshipManager =new Formula1ChampionshipManager();
F1ChampionshipGUI guiCode = new F1ChampionshipGUI();
These two "data sources" have nothing in common, so adding data to formula1ChampionshipManager
will not expose that data to guiCode
.
I'd remove the extends Formula1ChampionshipManager
from F1ChampionshipGUI
and simply pass it an instance of Formula1ChampionshipManager
directly. This is basic programming concept, see Passing Information to a Method or a Constructor for more details.
Having said that, you have a litany of other issues. Unless you have a very specific requirement, don't mix console and GUI workflows together. They have very different requirements.
I would strongly recommend having a look at:
You should then take a look at:
You'll also want to be familiar with:
because without those concepts, nothing I'm about to do will make any sense.
Because they weren't provided, I created my own Formula1ChampionshipManager
and Formula1Driver
classes...
public class Formula1Driver {
private String driverName;
private String driverTeam;
private String driverLocation;
private int firstPositions;
private int secondPositions;
private int thirdPositions;
private int racesParticipated;
private int points;
public Formula1Driver(String driverName, String driverTeam, String driverLocations, int firstPositions, int secondPositions, int thirdPositions, int racesParticipated, int points) {
this.driverName = driverName;
this.driverTeam = driverTeam;
this.driverLocation = driverLocations;
this.firstPositions = firstPositions;
this.secondPositions = secondPositions;
this.thirdPositions = thirdPositions;
this.racesParticipated = racesParticipated;
this.points = points;
}
public String getDriverName() {
return driverName;
}
public String getDriverTeam() {
return driverTeam;
}
public String getDriverLocation() {
return driverLocation;
}
public int getFirstPositions() {
return firstPositions;
}
public int getSecondPositions() {
return secondPositions;
}
public int getThirdPositions() {
return thirdPositions;
}
public int getRacesParticipated() {
return racesParticipated;
}
public int getPoints() {
return points;
}
}
public class Formula1ChampionshipManager {
private List<Formula1Driver> drivers;
public Formula1ChampionshipManager() {
drivers = new ArrayList<>();
}
public int size() {
return drivers.size();
}
public Formula1Driver getDriverAt(int index) {
return drivers.get(index);
}
public void add(Formula1Driver driver) {
drivers.add(driver);
// This is where I'd employee an observer pattern to notify
// interested parties that a driver was added
}
public void remove(Formula1Driver driver) {
drivers.remove(driver);
// This is where I'd employee an observer pattern to notify
// interested parties that a driver was removed
}
}
This formed the bases of the rest of the solution.
Because it's easier to do, I created my own custom TableModel
, which uses the Formula1ChampionshipManager
as its source of data.
public class Formula1DriverTableModel extends AbstractTableModel {
private Formula1ChampionshipManager manager;
private String[] columnNames = new String[]{"Name", "Team", "Location", "First positions", "Second positions", "Third positions", "Races participated", "Points"};
public Formula1DriverTableModel(Formula1ChampionshipManager manager) {
this.manager = manager;
}
public Formula1ChampionshipManager getManager() {
return manager;
}
@Override
public int getRowCount() {
return getManager().size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int column) {
return columnNames[column];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Formula1Driver driver = getManager().getDriverAt(rowIndex);
switch (columnIndex) {
case 0:
return driver.getDriverName();
case 1:
return driver.getDriverTeam();
case 2:
return driver.getDriverLocation();
case 3:
return driver.getFirstPositions();
case 4:
return driver.getSecondPositions();
case 5:
return driver.getThirdPositions();
case 6:
return driver.getRacesParticipated();
case 7:
return driver.getPoints();
}
return null;
}
}
This is an example of delegation and dependency injection (it also forms part of a different pattern, but you're probably somewhat overloaded by now)
nb: With an addition of an observer pattern directly to Formula1ChampionshipManager
, Formula1DriverTableModel
could register itself to be notified when drivers are added or removed and trigger appropriate change events via it's own observer pattern, but I took this as been out of context to the question
Then I created a "master" component to act as the "main" UI...
public class MasterPane extends JPanel {
private JTable table;
private Formula1DriverTableModel model;
private Formula1ChampionshipManager manager;
public MasterPane(Formula1ChampionshipManager manager) {
this.manager = manager;
setLayout(new BorderLayout());
model = new Formula1DriverTableModel(manager);
table = new JTable();
table.setAutoCreateRowSorter(true);
table.setModel(model);
List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
sortKeys.add(new RowSorter.SortKey(7, SortOrder.ASCENDING));
sortKeys.add(new RowSorter.SortKey(0, SortOrder.ASCENDING));
sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));
table.getRowSorter().setSortKeys(sortKeys);
add(new JScrollPane(table));
JPanel actions = new JPanel(new GridBagLayout());
JButton add = new JButton("Add");
JButton delete = new JButton("Delete");
JButton save = new JButton("Save");
JButton load = new JButton("Load");
actions.add(add);
actions.add(delete);
actions.add(save);
actions.add(load);
add(actions, BorderLayout.SOUTH);
add.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// This is likely going to be a dialog of some kind
// which presents the form to the user ... possibly
// passing the manager, maybe not. I might wait till
// the form is completed and ascertain the appropriate
// course of action based on the state of the dialog
}
});
delete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Get the selected index of the table and remove
// the driver at that location
}
});
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Call the management functionality
JOptionPane.showMessageDialog(MasterPane.this, "All you data belong to us", "Saved", JOptionPane.INFORMATION_MESSAGE);
}
});
load.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Call the management functionality
JOptionPane.showMessageDialog(MasterPane.this, "All you data now loaded", "Loaded", JOptionPane.INFORMATION_MESSAGE);
}
});
}
public Formula1ChampionshipManager getManager() {
return manager;
}
}
This presents a list of the drivers and some actions the user can take. You will note that the table will automatically sort the drivers. Since I didn't have the requirements for this, I sorted them by points
, name
and team
. This demonstrates the power using something like JTable
s inbuilt sorting capabilities.
And finally, I built the Formula1ChampionshipManager
, populated it and build the UI...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Formula1ChampionshipManager manager = new Formula1ChampionshipManager();
manager.add(new Formula1Driver("Hare", "H1", "", 0, 1, 0, 1, 50));
manager.add(new Formula1Driver("Tortus", "T1", "", 1, 0, 0, 1, 100));
JFrame frame = new JFrame();
frame.add(new MasterPane(manager));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
What's important to note here is, "Hare" is added first, so it's the first entry in our list, but in the UI, "Torus" is listed first 😱
But wait, where's edit?!
You can make the table editable and allow the user to modify the row data directly! See if you can figure out how to do that, hint, it's part of the TableModel
;)
Upvotes: 2