【问题标题】:How do I add an ActionListener to a JCheckBox?如何将 ActionListener 添加到 JCheckBox?
【发布时间】:2021-06-24 17:58:52
【问题描述】:

问题

所以我的程序接收一个 .csv 文件并加载数据并显示它。加载数据时,它会为数据中的每个列标题创建一个新的JCheckBox。如何添加ActionListener 以便当用户勾选/取消勾选任何框时,它应该执行特定功能?

加载数据时,通过代码更新JPanel

    public void updateChecklistPanel(){

        checklistPanel.removeAll();
        checklistPanel.setLayout(new GridLayout(currentData.getColumnNames().length, 1, 10, 0));
        for (String columnName : currentData.getColumnNames()){
            JCheckBox checkBox = new JCheckBox();
            checkBox.setText(columnName);
            checklistPanel.add(checkBox);
        }
        checklistPanel.revalidate();
        checklistPanel.repaint();
    }

我在底部还有以下内容:

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == newDataFrameItem){
            newFile();
            System.out.println("New DataFrame Loaded in");
        }
        if (e.getSource() == loadDataFrameItem){
            loadFile();
            System.out.println(".csv Data loaded into DataFrame.");
        }
        if (e.getSource() == saveDataFrameItem){
            System.out.println("Saved the data to a .csv file");
        }

    }

我想要做的是,当取消选中复选框时,它应该隐藏JTable 中的一列,并且在选中时,它应该重新显示该列。

当前解决方案

我想出的解决方案是创建一个变量allColumnHeaders,它是一个字符串的ArrayList。然后我还有一个变量shownColumnHeaders,它是一个布尔数组列表。当用户想要显示/隐藏列时,showColumn(String columnName)hideColumn(String columnName) 函数会在 allColumnHeaders 中找到列 Name 的索引,并将 shownColumnHeaders 中索引的布尔值设置为 true/false。

它继续创建一个新的表模型,其中仅当该列的布尔值为 true 时才添加列。然后它将表的模型设置为新的表模型。

以下代码如下:

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class MRE extends JPanel {

    private static JTable table;
    private static ArrayList<String> allColumnHeaders = new ArrayList<>();
    private static ArrayList<Boolean> shownColumnHeaders = new ArrayList<>();

    private static void createAndShowGUI()
    {
        table = new JTable(5, 7);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );

        JPanel buttons = new JPanel( new GridLayout(0, 1) );

        for (int i = 0; i < table.getColumnCount(); i++) {
            String column = table.getColumnName(i);
            allColumnHeaders.add(column);
            JCheckBox checkBox = new JCheckBox(column);

            checkBox.addActionListener(event -> {
                JCheckBox cb = (JCheckBox) event.getSource();
                if (cb.isSelected()) {
                    System.out.println(checkBox.getText() + " is now being displayed");
                    showColumn(checkBox.getText());
                } else {
                    System.out.println(checkBox.getText() + " is now being hidden");
                    hideColumn(checkBox.getText());
                }

                table.setModel(createTableModel());
            });

            checkBox.setSelected( true );
            buttons.add( checkBox );

            shownColumnHeaders.add(true);

        }

        JPanel wrapper = new JPanel();
        wrapper.add( buttons );

        JFrame frame = new JFrame("MRE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.add(wrapper, BorderLayout.LINE_END);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static DefaultTableModel createTableModel(){

        DefaultTableModel tableModel = new DefaultTableModel(0, 0);
        String[] columnValues = new String[1];
        for (int i = 0; i < shownColumnHeaders.size(); i++){
            if (shownColumnHeaders.get(i)){
                tableModel.addColumn(allColumnHeaders.get(i), columnValues);
            }
        }

        return tableModel;
    }

    public static void showColumn(String columnName){
        for (int i = 0; i < allColumnHeaders.size(); i++) {
            if (allColumnHeaders.get(i).equals(columnName)){
                shownColumnHeaders.set(i, true);
            }
        }
    }

    public static void hideColumn(String columnName){
        for (int i = 0; i < allColumnHeaders.size(); i++) {
            if (allColumnHeaders.get(i).equals(columnName)){
                shownColumnHeaders.set(i, false);
            }
        }
    }

    public static void main(String[] args) throws Exception
    {
        SwingUtilities.invokeLater( () -> createAndShowGUI() );
    }

}

【问题讨论】:

  • A JCheckBox 是 JToggleButton 的子类。您可以使用 addActionListener 方法为每个 JCheckBox 添加一个 ActionListener。
  • @GilbertLeBlanc 所以在生成checkBox的时候,我也在"checkBox.addActionListener(this);"这一行添加了但是我如何执行一个操作,因为我不知道它来自哪个源,因为它没有保存到变量或任何东西中
  • 它应该做一个特定的功能 - 定义特定的功能。功能是否通用。例如,在计算器面板上,如果您单击 1、2、3、4 等,功能相同,您会在显示屏上添加一个数字。不同的是添加到显示中的数字。所以在这种情况下,可以使用相同的 ActionListener。如果函数的列标题名称不同,那么您可以在 Hashmap 中预定义每个 ActionListener。
  • 您应该在创建 JCheckBox 时创建一个动作监听器。 checkBox.addActionListener(this) 将不起作用,因为您使用的是 e.getSource()==...,但源将是复选框。你想做什么?
  • @Ryan 这不是minimal reproducible example。我无法编译和测试该代码。 MRE 的重点是简化问题并展示您创建的可重用解决方案。我发布了一个答案,这不是一个答案,但它是一个仅包含相关组件的起点。您应该能够通过添加到每个复选框的 ActionListener 添加您的“可重用”类来控制列的可见性。如果您努力发布正确的 MRE,我将使用使用我的可重用类所需的 4 行代码来更新我的答案。

标签: java swing jframe jpanel actionlistener


【解决方案1】:

这只是演示如何创建一个基本的 MRE:

  1. csv 文件无关紧要。
  2. 模型中的数据不相关。
  3. 您的 loadFile、newFile 和 saveFile 按钮无关紧要。
  4. TableModel 无关

您的问题是关于将 ActionListener 添加到基于表的列动态创建的复选框中。

所以您只需要一个包含一些列和生成的复选框的表格。

import java.awt.*;
import javax.swing.*;

public class MRE extends JPanel
{
    private static void createAndShowGUI()
    {
        JTable table = new JTable(5, 7);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );

        JPanel buttons = new JPanel( new GridLayout(0, 1) );

        for (int i = 0; i < table.getColumnCount(); i++)
        {
            String column = table.getColumnName(i);
            JCheckBox checkBox = new JCheckBox("Display " + column);
            checkBox.setSelected( true );
            buttons.add( checkBox );
        }

        JPanel wrapper = new JPanel();
        wrapper.add( buttons );

        JFrame frame = new JFrame("MRE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.add(wrapper, BorderLayout.LINE_END);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        SwingUtilities.invokeLater( () -> createAndShowGUI() );
    }
}

如果您可以修改它以演示如何使用“可重用类”来管理列可见性,那么我将更新上面的代码以使用我的可重用类添加 4 行代码。

编辑:

对代码的建议改进:

  1. 使代码可重用和独立
  2. 不要使用静态方法
  3. 不要更改数据。

您最初的问题是:

How do I add an ActionListener to a JCheckBox?

为此,您需要一个类:

  1. 实现ActionListener
  2. 独立实现您需要的功能。

所以基本结构可能如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SomeFunction implements ActionListener
{
    private JTable table;

    public SomeFunction(JTable table)
    {
        this.table = table;
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if (e.getSource() instanceof AbstractButton)
        {
            String command = e.getActionCommand();
            AbstractButton button = (AbstractButton)e.getSource();

            if (button.isSelected())
                doSelected( command );
            else
                doUnselected( command );
        }
    }

    private void doSelected(String command)
    {
        System.out.println(command + " selected");
    }

    private void doUnselected(String command)
    {
        System.out.println(command + " unselected");
    }

    private static void createAndShowGUI()
    {
        JTable table = new JTable(5, 7);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane( table );

        JPanel buttons = new JPanel( new GridLayout(0, 1) );
        SomeFunction listener = new SomeFunction( table ); // added
//      TableColumnManager listener = new TableColumnManager(table, false);
//      ColumnListener listener = new ColumnListener();

        for (int i = 0; i < table.getColumnCount(); i++)
        {
            String column = table.getColumnName(i);
            JCheckBox checkBox = new JCheckBox("Display " + column);
            checkBox.setSelected( true );
            checkBox.setActionCommand( column ); // added
            checkBox.addActionListener( listener ); // added
            buttons.add( checkBox );
        }

        JPanel wrapper = new JPanel();
        wrapper.add( buttons );

        JFrame frame = new JFrame("MRE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.add(wrapper, BorderLayout.LINE_END);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args) throws Exception
    {
        SwingUtilities.invokeLater( () -> createAndShowGUI() );
    }
}

无论你的函数做什么,它只需要知道它应该作用的表。

所以尝试将你的代码重构为一个可重用的类。

如果你想使用 Gilberts 代码,那么你需要将 ColumnListener 类重构为一个单独的可重用自包含类。

最后你也可以试试我的可重用类。查看Table Column Manager 下载课程。

无论您决定使用什么可重用类,您只需更改上述示例中的一行代码(一旦您的功能包含在可重用类中)。

请注意,静态方法不会是最终类的一部分。它们只是为了简化 MRE 在单个类文件中的测试和发布。

希望这有助于未来的设计考虑。

【讨论】:

  • 上传了我已经实现的解决方案!
  • 谢谢您,我发现您帮助我解决问题的方式更有效、更有帮助。非常感谢
  • @Ryan,很高兴它有帮助。 TableColumnManager 代码比您的方法更复杂。这有几个原因:1)它试图处理列的重新排序。如果您隐藏/显示列,它将显示在其最后一个可见位置,而不是其在 TableModel 中定义的位置,并且 2) 它使用表的 TableColumnModel 中的原始 TableColumn。如果该表曾经被修改为具有该列的自定义渲染器/编辑器,这一点很重要。如果您重新创建 TableColumn,此信息将丢失。
【解决方案2】:

简介

我花了一段时间,但我想出了以下JTable GUI。这是开始显示。

这是我删除项目描述后的 GUI。

这是我删除商品价格后的 GUI。

这是我添加列后的 GUI。

说明

我创建了一个 Item 类来保存一个项目。

我创建了一个Inventory 类来保存Item 实例的列表和列标题的String 数组。

我创建了JFrame 和两个JPanels。一个JPanel 持有JTable,另一个持有JCheckBoxes。我使用 Swing 布局管理器创建了JPanels

到目前为止,还很基础。创建JTable 需要一些努力。我想将商品价格显示为货币,但这对于这个示例 GUI 来说并不重要。

我创建了一个ActionListener 来在JTable 中添加和删除列。我不得不做一些实验。 TableColumnModeladdColumn 方法将列追加到表中。

我必须创建一个DisplayTableColumn 类来保存TableColumn 和一个告诉我是否显示TableColumn 的布尔值。我最终从JTable 中删除了所有列,并将所有列添加回JTable,以便我可以保持列顺序。我可能运行了 100 次测试才能让这段代码正常工作。

代码

这是完整的可运行代码。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

public class JCheckBoxTableGUI implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new JCheckBoxTableGUI());
    }
    
    private final Inventory inventory;
    
    private final InventoryTableModel tableModel;
    
    private JFrame frame;
    
    private JTable table;
    
    public JCheckBoxTableGUI() {
        this.tableModel = new InventoryTableModel();
        this.inventory = new Inventory();
        
        String[] columns = inventory.getTableHeader();
        for (String column : columns) {
            tableModel.addColumn(column);
        }
        
        List<Item> items = inventory.getInventory();
        for (Item item : items) {
            Object[] object = new Object[5];
            object[0] = item.getItemNumber();
            object[1] = item.getItemName();
            object[2] = item.getItemDescription();
            object[3] = item.getItemQuantity();
            object[4] = item.getItemPrice();
            tableModel.addRow(object);
        }
    }

    @Override
    public void run() {
        frame = new JFrame("JCheckBox Table GUI");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createTablePanel(), BorderLayout.CENTER);
        frame.add(createSelectionPanel(), BorderLayout.AFTER_LINE_ENDS);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createTablePanel() {
        JPanel panel = new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        table = new JTable(tableModel);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.getColumnModel().getColumn(0).setPreferredWidth(100);
        table.getColumnModel().getColumn(1).setPreferredWidth(150);
        table.getColumnModel().getColumn(2).setPreferredWidth(150);
        table.getColumnModel().getColumn(3).setPreferredWidth(100);
        table.getColumnModel().getColumn(4).setPreferredWidth(100);
        JScrollPane scrollPane = new JScrollPane(table);
        scrollPane.setPreferredSize(new Dimension(620, 300));
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }
    
    private JPanel createSelectionPanel() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        JPanel innerPanel = new JPanel(new GridLayout(0, 1, 5, 5));
        
        ColumnListener listener = new ColumnListener(this);
        String[] columns = inventory.getTableHeader();
        for (String column : columns) {
            JCheckBox checkBox = new JCheckBox("Display " +  column);
            checkBox.addActionListener(listener);
            checkBox.setActionCommand(column);
            checkBox.setSelected(true);
            innerPanel.add(checkBox);
        }
        
        panel.add(innerPanel);
        
        return panel;
    }
    
    public JTable getTable() {
        return table;
    }
    
    public JFrame getFrame() {
        return frame;
    }
    
    public class ColumnListener implements ActionListener {
        
        private final JCheckBoxTableGUI frame;
        
        private final List<DisplayTableColumn> displayColumns;

        public ColumnListener(JCheckBoxTableGUI frame) {
            this.frame = frame;
            this.displayColumns = new ArrayList<>();
            
            TableColumnModel tcm = frame.getTable().getColumnModel();
            for (int index = 0; index < tcm.getColumnCount(); index++) {
                TableColumn tc = tcm.getColumn(index);
                displayColumns.add(new DisplayTableColumn(tc, true));
            }
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            JCheckBox checkBox =  (JCheckBox) event.getSource();
            String column = event.getActionCommand();
            TableColumnModel tcm = frame.getTable().getColumnModel();
            
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (dtc.isShowTableColumn()) {
                    tcm.removeColumn(dtc.getTableColumn());
                }
            }
            
            int columnIndex = getColumnIndex(column);
            displayColumns.get(columnIndex).setShowTableColumn(
                    checkBox.isSelected());
            
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (dtc.isShowTableColumn()) {
                    tcm.addColumn(dtc.getTableColumn());
                }
            }
            
            frame.getFrame().pack();
        }
        
        private int getColumnIndex(String column) {
            for (int index = 0; index < displayColumns.size(); index++) {
                DisplayTableColumn dtc = displayColumns.get(index);
                if (column.equals(dtc.getTableColumn().getHeaderValue())) {
                    return index;
                }
            }
            
            return -1;
        }
        
    }
    
    public class DisplayTableColumn {
        
        private boolean showTableColumn;
        
        private final TableColumn tableColumn;

        public DisplayTableColumn(TableColumn tableColumn, boolean showTableColumn) {
            this.tableColumn = tableColumn;
            this.showTableColumn = showTableColumn;
        }

        public boolean isShowTableColumn() {
            return showTableColumn;
        }

        public void setShowTableColumn(boolean showTableColumn) {
            this.showTableColumn = showTableColumn;
        }

        public TableColumn getTableColumn() {
            return tableColumn;
        }
        
    }
    
    public class InventoryTableModel extends DefaultTableModel {

        private static final long serialVersionUID = 1L;

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex <= 2) {
                return String.class;
            } else if (columnIndex == 3) {
                return Integer.class;
            } else {
                return Integer.class;
            }
        }

    }
    
    public class Inventory {
        
        private final List<Item> inventory;
        
        private final String[] tableHeader;
        
        public Inventory() {
            this.tableHeader = new String[] { "Item Number", "Item Name", 
                    "Item Description", "Item Quantity",
                    "Item Price" };
            
            this.inventory = new ArrayList<>();
            
            inventory.add(new Item("X101111", "Samsung Camera", " ", 20, 69.99));
            inventory.add(new Item("X101112", "Samsung Monitor", " ", 10, 279.99));
            inventory.add(new Item("X101113", "Samsung Smartphone", " ", 110, 599.99));
            inventory.add(new Item("X101114", "Apple Watch", " ", 20, 1259.99));
            inventory.add(new Item("X101115", "Sony Playstation 5", " ", 0, 399.99));
        }

        public String[] getTableHeader() {
            return tableHeader;
        }

        public List<Item> getInventory() {
            return inventory;
        }
        
    }
    
    public class Item {
        
        private int itemPrice;
        private int itemQuantity;
        
        private final String itemNumber;
        private final String itemName;
        private final String itemDescription;
        
        public Item(String itemNumber, String itemName, 
                String itemDescription, int itemQuantity, double itemPrice) {
            this.itemNumber = itemNumber;
            this.itemName = itemName;
            this.itemDescription = itemDescription;
            this.itemQuantity = itemQuantity;
            setItemPrice(itemPrice);
        }

        public int getItemPrice() {
            return itemPrice;
        }

        public void setItemPrice(double itemPrice) {
            this.itemPrice = (int) Math.round(itemPrice * 100.0);
        }

        public int getItemQuantity() {
            return itemQuantity;
        }

        public void setItemQuantity(int itemQuantity) {
            this.itemQuantity = itemQuantity;
        }

        public String getItemNumber() {
            return itemNumber;
        }

        public String getItemName() {
            return itemName;
        }

        public String getItemDescription() {
            return itemDescription;
        }
        
    }

}

【讨论】:

  • 老实说,这真是太棒了。很容易理解和遵循你的代码。老实说,非常感谢你。
猜你喜欢
  • 1970-01-01
  • 2014-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多