【问题标题】:How to populate JTable with an existing ArrayList of objects?如何用现有的 ArrayList 对象填充 JTable?
【发布时间】:2022-01-10 08:28:45
【问题描述】:

作为一项任务,我需要制作一个 Swing GUI。在第一部分中,我创建了一个对象 (Formula1Driver) 的 ArrayList (f1Driver)。目前需要的是对所述数组列表进行排序并在 GUI 中将其显示为JTable。我已经制作了一个JButton,当按下它时它应该会排序和显示。

但是,一旦按下它只会显示表格标题而不是数组列表中的信息,我应该怎么做?我已经包含了 GUI 类和下面的主类。

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);

            }
        });
    }
}

【问题讨论】:

  • 我要改变的东西太多了。从哪儿开始?您的 GUI 不应该只显示 JTable,它还应该允许用户执行您显示到控制台的菜单中的所有操作,因为您不应该在同一个应用程序中同时使用控制台和 GUI 进行用户交互。通常你不应该使用空的layout。如果您需要帮助调试代码,那么我认为您应该发布minimal reproducible example。
  • 因此,从概念上讲,您的代码可以工作,问题出在数据源上。您的 GUI 是从 Formula1ChampionshipManager 扩展而来的,我假设它充当某种数据源,问题是您创建了此数据源的两个实例,因此 GUI 可能不知道其他数据源具有什么信息。所以,是的,Abra 的评论实际上是正确的 - 放弃控制台输入并通过 GUI 构建所有管理
  • 或者,从F1ChampionshipGUI 中删除extends Formula1ChampionshipManager,然后将它需要的数据直接传递给它

标签: java swing arraylist jtable


【解决方案1】:

我怀疑,“主要”问题来自数据共享问题。

基本上,F1ChampionshipGUI 是从 Formula1ChampionshipManager 扩展而来的,但是您创建了一个单独的 Formula1ChampionshipManager 实例

Formula1ChampionshipManager formula1ChampionshipManager =new Formula1ChampionshipManager();
F1ChampionshipGUI guiCode = new F1ChampionshipGUI();

这两个“数据源”没有任何共同之处,因此向formula1ChampionshipManager 添加数据不会将该数据暴露给guiCode。

我会从F1ChampionshipGUI 中删除extends Formula1ChampionshipManager,然后直接将Formula1ChampionshipManager 的实例传递给它。这是基本的编程概念,详情请参阅Passing Information to a Method or a Constructor。

话虽如此,您还有一连串其他问题。除非您有非常具体的要求,否则不要将控制台和 GUI 工作流程混合在一起。他们有非常不同的要求。

我强烈建议您看看:

然后你应该看看:

您还需要熟悉:

因为没有这些概念,我要做的任何事情都将毫无意义。

因为没有提供它们,所以我创建了自己的 Formula1ChampionshipManager 和 Formula1Driver 类...

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
    }
}

这构成了其余解决方案的基础。

因为这样做更容易,我创建了自己的自定义TableModel,它使用Formula1ChampionshipManager 作为其数据源。

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;
    }

}

这是一个委托和依赖注入的例子(它也构成了不同模式的一部分,但你现在可能有点超载了)

nb:通过将观察者模式直接添加到Formula1ChampionshipManager,Formula1DriverTableModel 可以注册自己以在添加或删除驱动程序时收到通知,并通过它自己的观察者模式触发适当的更改事件,但我接受了这与问题无关

然后我创建了一个“主”组件来充当“主”用户界面...

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;
    }

}

这会显示驱动程序列表和用户可以采取的一些操作。您会注意到该表将自动对驱动程序进行排序。由于我没有这方面的要求,我将它们按points、name 和team 排序。这展示了使用类似JTables 的内置排序功能的强大功能。

最后,我构建了Formula1ChampionshipManager,填充它并构建了 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);
    }
});

这里需要注意的是,“Hare”是最先添加的,所以它是我们列表中的第一个条目,但在 UI 中,“Torus”是第一个列出的?

等等,编辑在哪里?!

您可以使表格可编辑并允许用户直接修改行数据!看看你是否能弄清楚如何做到这一点,提示,它是TableModel 的一部分;)

【讨论】:

  • ""Torus" 列在首位" - 发生了什么?
  • @BlastoiseOpressor 看排序键,按points、name、team排序
猜你喜欢
  • 2017-12-29
  • 2012-01-27
  • 2018-12-14
  • 1970-01-01
  • 2012-10-31
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多