[英]How do I add an ActionListener to a JCheckBox?
So my program takes in a.csv file and loads the data and displays it.所以我的程序接受一个.csv 文件并加载数据并显示它。 When data is loaded in, it creates a new JCheckBox
for every column header there is in the data.加载数据时,它会为数据中的每一列 header 创建一个新的JCheckBox
。 How do I add an ActionListener
such that when the user ticks/unticks any of the boxes, it should do a certain function?如何添加一个ActionListener
以便当用户勾选/取消勾选任何框时,它应该执行某个 function?
When data is loaded in, it updates the JPanel
by the code:加载数据时,它会通过以下代码更新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();
}
I also have the following at the bottom:我在底部还有以下内容:
@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");
}
}
What I'm trying to do is that when a checkbox is unticked, it should hide a column in the JTable
and when ticked, it should redisplay the column.我想要做的是,当取消选中复选框时,它应该隐藏JTable
中的一列,并且在勾选时,它应该重新显示该列。
The solution that I have come up with is to make a variable allColumnHeaders
that is an ArrayList of Strings.我想出的解决方案是创建一个变量allColumnHeaders
,它是字符串的 ArrayList。 I then also have a variable shownColumnHeaders
that is an ArrayList of Booleans.然后,我还有一个变量shownColumnHeaders
,它是布尔值的 ArrayList。 When the user wants to show/hide a column, the showColumn(String columnName)
and hideColumn(String columnName)
function finds the index of the column Name in allColumnHeaders
and sets the Boolean value of the index in shownColumnHeaders
to either true/false.当用户想要显示/隐藏列时, showColumn(String columnName)
和hideColumn(String columnName)
function 在allColumnHeaders
中查找列 Name 的索引,并将 shownColumnHeaders 中索引的shownColumnHeaders
值设置为 true/false。
It the proceeds to create a new table model where the columns are only added if the Boolean value for that column is true.它将继续创建一个新表 model,其中仅当该列的 Boolean 值为 true 时才添加列。 It will then set the model for the table to the new table model.然后它将表的 model 设置为新表 model。
The code for the following is show below:以下代码如下所示:
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() );
}
}
It took me a while, but I came up with the following JTable
GUI.我花了一段时间,但我想出了以下JTable
GUI。 Here's the starting display.这是开始的显示。
Here's the GUI after I remove the item description.这是我删除项目描述后的 GUI。
Here's the GUI after I remove the item price.这是我删除商品价格后的 GUI。
Here's the GUI after I add the columns back.这是我添加列后的 GUI。
I created an Item
class to hold one item.我创建了一个Item
class 来容纳一个项目。
I created an Inventory
class to hold a List of Item
instances and a String
array of the column headers.我创建了一个Inventory
class 来保存一个Item
实例列表和一个列标题的String
数组。
I created the JFrame
and two JPanels
.我创建了JFrame
和两个JPanels
。 One JPanel
holds the JTable
and the other holds the JCheckBoxes
.一个JPanel
持有JTable
,另一个持有JCheckBoxes
。 I used Swing layout managers to create the JPanels
.我使用 Swing 布局管理器来创建JPanels
。
So far, so basic.到目前为止,很基本。 Creating the JTable
took a bit of effort.创建JTable
需要一些努力。 I wanted to display the item price as currency, but that wasn't important for this example GUI.我想将商品价格显示为货币,但这对于这个示例 GUI 来说并不重要。
I created an ActionListener
to add and remove columns from the JTable
.我创建了一个ActionListener
来添加和删除JTable
中的列。 I had to experiment a bit.我不得不做一些实验。 The TableColumnModel
addColumn
method appends the column to the table. TableColumnModel
addColumn
方法将列附加到表中。
I had to create a DisplayTableColumn
class to hold a TableColumn
and a boolean that tells me whether or not to display the TableColumn
.我必须创建一个DisplayTableColumn
class 来保存一个TableColumn
和一个告诉我是否显示TableColumn
的 boolean 。 I wound up removing all the columns from the JTable
and adding all the columns back to the JTable
so that I could maintain the column sequence.我最终从JTable
中删除了所有列,并将所有列添加回JTable
以便我可以保持列顺序。 I probably ran 100 tests before I could get this code to work.我可能运行了 100 次测试才能让这段代码工作。
Here's the complete runnable code.这是完整的可运行代码。
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;
}
}
}
This only demonstrates how to create a basic MRE:这仅演示了如何创建一个基本的 MRE:
Your question is about adding an ActionListener to dynamically created checkboxes based on the columns of the table.您的问题是关于将 ActionListener 添加到基于表的列动态创建的复选框中。
So all you need is a table with some columns and the resulting checkboxes.因此,您所需要的只是一个包含一些列和生成的复选框的表格。
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() );
}
}
If you can modify this to demonstrate how to use your "reusable class" to manage column visibility, then I will update the above code to use my reusable class with 4 additional lines of code.如果您可以修改它以演示如何使用“可重用类”来管理列可见性,那么我将更新上面的代码以使用我的可重用 class 和另外 4 行代码。
Edit:编辑:
Suggested improvements to your code:对代码的建议改进:
Your original question was:你原来的问题是:
How do I add an ActionListener to a JCheckBox?
So to do that you need a class that:所以要做到这一点,你需要一个 class :
ActionListener
实现一个ActionListener
So the basic structure could be like the following:所以基本结构可能如下所示:
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() );
}
}
Whatever your function does it only needs to know about the table it should act upon.无论您的 function 做什么,它只需要知道它应该操作的表。
So try to restructure your code into a reusable class.因此,尝试将您的代码重组为可重用的 class。
If you want to use Gilberts code, then you need to restructure the ColumnListener
class into a separate reusable self contained class.如果要使用 Gilberts 代码,则需要将ColumnListener
class 重组为单独的可重用自包含 class。
Finally you can also try my reusable class.最后你也可以试试我的可重复使用的 class。 Check out Table Column Manager for the class to download.查看 class 的表格列管理器以进行下载。
Whatever reusable class you decide to use, you will only need to change a single line of code from the above example (once your functionality is contained in a reusable class).无论您决定使用什么可重用 class,您只需更改上述示例中的一行代码(一旦您的功能包含在可重用类中)。
Note the static methods would not be part of the final class.请注意 static 方法不会成为最终 class 的一部分。 They are only there so simplify testing and posting of an MRE in a single class file.它们只是为了简化在单个 class 文件中测试和发布 MRE。
Hope this helps with future design considerations.希望这有助于未来的设计考虑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.