使JButton在JTable中可单击

时间:2023-01-17 13:43:43

Here is the screenshot of what I want to do :

下面是我想做的截图:

使JButton在JTable中可单击

What's happening there is the JButton shows correctly but nothing happens when I click on it. After some search, I've found that the Object returned by table.getValueAt() is a String instead of a JButton...

所发生的事情是JButton显示正确但是当我点击它时什么也没有发生。在搜索之后,我发现表. getvalueat()返回的对象是一个字符串,而不是一个JButton……

Here is the code :

这里是代码:

tblResult = new JTable(data,cols) {
    public TableCellRenderer getCellRenderer( int row, int column ) {
        return new ClientsTableRenderer();
    }
};

I use this for populating at run-time the JTable : (tblResult is now Clients.rblResult)

我使用它在运行时填充JTable: (tblResult现在是client . rblresult)

SwingUtilities.invokeLater( new Runnable() {
    public void run() { 

        DefaultTableModel aModel = new DefaultTableModel() {
            //setting the jtable read only
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }               
        };


    String[] cols = {"N°","Société", "TVA", "CP", "Ville", ""};
    aModel.setColumnIdentifiers(cols);

    Object[] temp = new Object[6];
    for(int i=0;i<result.length;i++) {

        temp[0] = result[i].custNumber;
        temp[1] = result[i].name;
        temp[2] = result[i].tva;
        temp[3] = result[i].cp;
        temp[4] = result[i].city;
        temp[5] = "Consulter";

        aModel.addRow(temp);

    }

    Clients.tblResult.setModel(aModel);

    Clients.tblResult.addMouseListener(new JTableButtonMouseListener(Clients.tblResult));
    }}  
); 

Here the ClientsTableRenderer class

这里ClientsTableRenderer类

public class ClientsTableRenderer extends JPanel implements TableCellRenderer {
    @Override
    public Component getTableCellRendererComponent( final JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        setBackground(Color.WHITE);
        if(column < 5) {
            JLabel label =  new JLabel(value.toString());
            JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,9));
            panel.setBackground(Color.WHITE);
            panel.add(label);
            this.add( panel);
        } else {

            JButton button = new JButton(value.toString());
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    System.out.println("Clicked !");
                }
            });
            JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER,0,3));
            panel.setBackground(Color.WHITE);
            panel.add(button);
            this.add(panel);
        }


        return this;
    }


}

And finaly, the JTableButtonMouseListener() :

最后,JTableButtonMouseListener():

public class JTableButtonMouseListener extends MouseAdapter {
      private final JTable table;

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

      @Override public void mouseClicked(MouseEvent e) {
        int column = table.getColumnModel().getColumnIndexAtX(e.getX());
        int row    = e.getY()/table.getRowHeight(); 
        System.out.println("Col :"+column + "row:"+row);

        if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() && column >= 0) {
          Object value = table.getValueAt(row, column);
          System.out.println("Value :"+value.getClass().getName());
          if (value instanceof JButton) {
            ((JButton)value).doClick();
          }

        }
      }
    }

I'm kindly new to Java, help would be very much appreciated :)

我是Java的新手,非常感谢您的帮助。)

Thanks in advance !

提前谢谢!

6 个解决方案

#1


16  

This Table Button Column from Rob Camick may fit your needs.

Rob Camick的这个表格按钮列可能适合您的需要。

#2


9  

The problem is that the JButton no longer exists when painted in the table. Those components are only used to create a 'stamp' when the table is rendered. There is no actual button present.

问题是,当在表中绘制时,JButton不再存在。这些组件仅用于在呈现表时创建“stamp”。这里没有实际的按钮。

There is a way to allow you to click on the button, and still keep your table non-editable, but it is far from proper code. Just a quick outline for a possible solution (I do not have the time at this moment to give a full code example)

有一种方法可以让您单击按钮,但仍然保持表不可编辑,但这远非正确的代码。简单介绍一下可能的解决方案(我现在没有时间给出完整的代码示例)

  • attach a mouse listener to the table
  • 将鼠标监听器附加到表上
  • when you receive a mouse click, determine the cell in which the mouse click occurred
  • 当您收到鼠标单击时,确定鼠标单击所发生的单元格。
  • ask the table renderer for the component for that cell
  • 向表呈现程序请求该单元格的组件
  • use the location of the mouse click to determine whether a button is present in the component from the previous step at that particular location
  • 使用鼠标单击的位置来确定组件中是否存在上一步在该特定位置的按钮
  • if so, do the click through the button api (the doClick method)
  • 如果是,通过按钮api (doClick方法)进行单击

And this is not even the dirty part of the code. Since your renderer (hopefully) does not return a new JButton each time, you should in your ActionListener which is attached to the JButton keep track of for which component the click actually occurred. A possible solution is to keep a reference to the table model value for which you the last time created a JButton (so in the getCellRendererComponent method keep track of the row/column), but I am unsure whether this is the best approach.

这甚至不是代码中最脏的部分。由于您的渲染器(希望如此)不会每次都返回一个新的JButton,所以您应该在您的ActionListener中(它附加在JButton上)跟踪单击实际发生的组件。一个可能的解决方案是,将一个引用保存到您上次创建JButton的表模型值(因此,在getCellRendererComponent方法中保持对行/列的跟踪),但是我不确定这是否是最佳方法。

As said, a possible solution but far from elegant.

如前所述,一个可能的解决方案,但远非优雅。

The easiest way is to just make that one column editable and use an editor, as pointed out in other answers

最简单的方法是让一个列可编辑并使用编辑器,如其他答案所示

#3


8  

Try this:

试试这个:

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

public class TableWithButtonDemo
{
  private JFrame frame = new JFrame("Table Demo");
  private String[] columnNames = { "String", "Integer", "Float", "" };
  private Object[][] data = { { "Dummy", new Integer(12), new Float(12.15), "Consulter" } };
  private TableModel model = new DefaultTableModel(data, columnNames)
  {
    private static final long serialVersionUID = 1L;

    public boolean isCellEditable(int row, int column)
    {
      return column == 3;
    }
  };
  private JTable table = new JTable(model);

  public TableWithButtonDemo()
  {
    table.getColumnModel().getColumn(3).setCellRenderer(new ClientsTableButtonRenderer());
    table.getColumnModel().getColumn(3).setCellEditor(new ClientsTableRenderer(new JCheckBox()));
    table.setPreferredScrollableViewportSize(table.getPreferredSize());
    table.setShowHorizontalLines(true);
    table.setShowVerticalLines(false);

    JScrollPane scroll = new JScrollPane(table);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(scroll);
    frame.pack();
    frame.setLocation(150, 150);
    frame.setVisible(true);
  }

  public static void main(String[] args) throws Exception
  {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    EventQueue.invokeLater(new Runnable()
    {
      public void run()
      {
        new TableWithButtonDemo();
      }
    });
  }

  class ClientsTableButtonRenderer extends JButton implements TableCellRenderer
  {
    public ClientsTableButtonRenderer()
    {
      setOpaque(true);
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {
      setForeground(Color.black);
      setBackground(UIManager.getColor("Button.background"));
      setText((value == null) ? "" : value.toString());
      return this;
    }
  }
  public class ClientsTableRenderer extends DefaultCellEditor
  {
    private JButton button;
    private String label;
    private boolean clicked;
    private int row, col;
    private JTable table;

    public ClientsTableRenderer(JCheckBox checkBox)
    {
      super(checkBox);
      button = new JButton();
      button.setOpaque(true);
      button.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          fireEditingStopped();
        }
      });
    }
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
    {
      this.table = table;
      this.row = row;
      this.col = column;

      button.setForeground(Color.black);
      button.setBackground(UIManager.getColor("Button.background"));
      label = (value == null) ? "" : value.toString();
      button.setText(label);
      clicked = true;
      return button;
    }
    public Object getCellEditorValue()
    {
      if (clicked)
      {
        JOptionPane.showMessageDialog(button, "Column with Value: "+table.getValueAt(row, 1) + " -  Clicked!");
      }
      clicked = false;
      return new String(label);
    }

    public boolean stopCellEditing()
    {
      clicked = false;
      return super.stopCellEditing();
    }

    protected void fireEditingStopped()
    {
      super.fireEditingStopped();
    }
  }

}

#4


3  

This articles provides an easier approach to your problem without adding MouseListeners and computing if the click is actually on the button or not:

本文提供了一种更简单的方法来解决您的问题,而不添加鼠标监听器和计算,如果单击实际上是否在按钮上:

http://web.archive.org/web/20100623105810/http://ivolo.mit.edu/post/A-Simple-Pattern-for-Embedding-Components-into-a-Swing-JTable.aspx

http://web.archive.org/web/20100623105810/http:/ /ivolo.mit.edu/post/A-Simple-Pattern-for-Embedding-Components-into-a-Swing-JTable.aspx

#5


0  

Overload your Table model, and set isCellEditable(int, int) return false for the cells with buttons.

重载表模型,并为带有按钮的单元格设置isCellEditable(int, int)返回false。

It works great in with a MouseListener added to the table.

它非常适合添加到表中的鼠标监听器。

#6


0  

Here is my solution

这是我的解决方案

ButtonEditor.java

ButtonEditor.java

public abstract class ButtonEditor extends DefaultCellEditor implements ActionListener {
private static final long serialVersionUID = 1L;

/** The cell's row. */
protected int row;

/** The cell's column. */
protected int column;

/** The cell's column. */
protected JTable table;

/** The button we are editing. */
protected JButton button;

/** The panel used when editing. */
protected JPanel panel = new JPanel(new GridBagLayout());

/** Constructor */
public ButtonEditor() {super(new JCheckBox());}

/**
 * This method is called when the user try to modify a cell. 
 * In this case it will be called whenever the user click on the cell.
 * @param table
 * @param value
 * @param isSelected
 * @param row
 * @param column
 * @return JPanel The JPanel returned contains a JButton with an ActionListener. 
 */
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    this.row = row;
    this.column = column;
    this.table = table;
    button = (JButton) value;

    //prevent to add the action listener everytime the user click on the cell.
    if(button.getActionListeners().length == 0) button.addActionListener(this); 

    panel.add(button);
    panel.setBackground(table.getGridColor());
    return panel;
}

/**
 * Return a renderer for JButtons. The result is a button centered in the table's cell.
 * @return
 */
public static TableCellRenderer getRenderer() {
    return new TableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            JPanel panel = new JPanel(new GridBagLayout());
            panel.add((JButton) value);
            panel.setBackground(table.getGridColor());
            return panel;
        }
    };
}

}

}

And here is how to use it:

下面是如何使用它:

Demo.java

Demo.java

    table.setDefaultRenderer(JButton.class, ButtonEditor.getRenderer()); 
    table.setDefaultEditor(JButton.class, new ButtonEditor() {
        @Override
        public void actionPerformed(ActionEvent e) {

            //handle clicks here. for example:   
            if(column == 5) {
                System.out.Println(row);
                button.setFocusPainted(false);                  
            }
        }
    });

#1


16  

This Table Button Column from Rob Camick may fit your needs.

Rob Camick的这个表格按钮列可能适合您的需要。

#2


9  

The problem is that the JButton no longer exists when painted in the table. Those components are only used to create a 'stamp' when the table is rendered. There is no actual button present.

问题是,当在表中绘制时,JButton不再存在。这些组件仅用于在呈现表时创建“stamp”。这里没有实际的按钮。

There is a way to allow you to click on the button, and still keep your table non-editable, but it is far from proper code. Just a quick outline for a possible solution (I do not have the time at this moment to give a full code example)

有一种方法可以让您单击按钮,但仍然保持表不可编辑,但这远非正确的代码。简单介绍一下可能的解决方案(我现在没有时间给出完整的代码示例)

  • attach a mouse listener to the table
  • 将鼠标监听器附加到表上
  • when you receive a mouse click, determine the cell in which the mouse click occurred
  • 当您收到鼠标单击时,确定鼠标单击所发生的单元格。
  • ask the table renderer for the component for that cell
  • 向表呈现程序请求该单元格的组件
  • use the location of the mouse click to determine whether a button is present in the component from the previous step at that particular location
  • 使用鼠标单击的位置来确定组件中是否存在上一步在该特定位置的按钮
  • if so, do the click through the button api (the doClick method)
  • 如果是,通过按钮api (doClick方法)进行单击

And this is not even the dirty part of the code. Since your renderer (hopefully) does not return a new JButton each time, you should in your ActionListener which is attached to the JButton keep track of for which component the click actually occurred. A possible solution is to keep a reference to the table model value for which you the last time created a JButton (so in the getCellRendererComponent method keep track of the row/column), but I am unsure whether this is the best approach.

这甚至不是代码中最脏的部分。由于您的渲染器(希望如此)不会每次都返回一个新的JButton,所以您应该在您的ActionListener中(它附加在JButton上)跟踪单击实际发生的组件。一个可能的解决方案是,将一个引用保存到您上次创建JButton的表模型值(因此,在getCellRendererComponent方法中保持对行/列的跟踪),但是我不确定这是否是最佳方法。

As said, a possible solution but far from elegant.

如前所述,一个可能的解决方案,但远非优雅。

The easiest way is to just make that one column editable and use an editor, as pointed out in other answers

最简单的方法是让一个列可编辑并使用编辑器,如其他答案所示

#3


8  

Try this:

试试这个:

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

public class TableWithButtonDemo
{
  private JFrame frame = new JFrame("Table Demo");
  private String[] columnNames = { "String", "Integer", "Float", "" };
  private Object[][] data = { { "Dummy", new Integer(12), new Float(12.15), "Consulter" } };
  private TableModel model = new DefaultTableModel(data, columnNames)
  {
    private static final long serialVersionUID = 1L;

    public boolean isCellEditable(int row, int column)
    {
      return column == 3;
    }
  };
  private JTable table = new JTable(model);

  public TableWithButtonDemo()
  {
    table.getColumnModel().getColumn(3).setCellRenderer(new ClientsTableButtonRenderer());
    table.getColumnModel().getColumn(3).setCellEditor(new ClientsTableRenderer(new JCheckBox()));
    table.setPreferredScrollableViewportSize(table.getPreferredSize());
    table.setShowHorizontalLines(true);
    table.setShowVerticalLines(false);

    JScrollPane scroll = new JScrollPane(table);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(scroll);
    frame.pack();
    frame.setLocation(150, 150);
    frame.setVisible(true);
  }

  public static void main(String[] args) throws Exception
  {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    EventQueue.invokeLater(new Runnable()
    {
      public void run()
      {
        new TableWithButtonDemo();
      }
    });
  }

  class ClientsTableButtonRenderer extends JButton implements TableCellRenderer
  {
    public ClientsTableButtonRenderer()
    {
      setOpaque(true);
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {
      setForeground(Color.black);
      setBackground(UIManager.getColor("Button.background"));
      setText((value == null) ? "" : value.toString());
      return this;
    }
  }
  public class ClientsTableRenderer extends DefaultCellEditor
  {
    private JButton button;
    private String label;
    private boolean clicked;
    private int row, col;
    private JTable table;

    public ClientsTableRenderer(JCheckBox checkBox)
    {
      super(checkBox);
      button = new JButton();
      button.setOpaque(true);
      button.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          fireEditingStopped();
        }
      });
    }
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
    {
      this.table = table;
      this.row = row;
      this.col = column;

      button.setForeground(Color.black);
      button.setBackground(UIManager.getColor("Button.background"));
      label = (value == null) ? "" : value.toString();
      button.setText(label);
      clicked = true;
      return button;
    }
    public Object getCellEditorValue()
    {
      if (clicked)
      {
        JOptionPane.showMessageDialog(button, "Column with Value: "+table.getValueAt(row, 1) + " -  Clicked!");
      }
      clicked = false;
      return new String(label);
    }

    public boolean stopCellEditing()
    {
      clicked = false;
      return super.stopCellEditing();
    }

    protected void fireEditingStopped()
    {
      super.fireEditingStopped();
    }
  }

}

#4


3  

This articles provides an easier approach to your problem without adding MouseListeners and computing if the click is actually on the button or not:

本文提供了一种更简单的方法来解决您的问题,而不添加鼠标监听器和计算,如果单击实际上是否在按钮上:

http://web.archive.org/web/20100623105810/http://ivolo.mit.edu/post/A-Simple-Pattern-for-Embedding-Components-into-a-Swing-JTable.aspx

http://web.archive.org/web/20100623105810/http:/ /ivolo.mit.edu/post/A-Simple-Pattern-for-Embedding-Components-into-a-Swing-JTable.aspx

#5


0  

Overload your Table model, and set isCellEditable(int, int) return false for the cells with buttons.

重载表模型,并为带有按钮的单元格设置isCellEditable(int, int)返回false。

It works great in with a MouseListener added to the table.

它非常适合添加到表中的鼠标监听器。

#6


0  

Here is my solution

这是我的解决方案

ButtonEditor.java

ButtonEditor.java

public abstract class ButtonEditor extends DefaultCellEditor implements ActionListener {
private static final long serialVersionUID = 1L;

/** The cell's row. */
protected int row;

/** The cell's column. */
protected int column;

/** The cell's column. */
protected JTable table;

/** The button we are editing. */
protected JButton button;

/** The panel used when editing. */
protected JPanel panel = new JPanel(new GridBagLayout());

/** Constructor */
public ButtonEditor() {super(new JCheckBox());}

/**
 * This method is called when the user try to modify a cell. 
 * In this case it will be called whenever the user click on the cell.
 * @param table
 * @param value
 * @param isSelected
 * @param row
 * @param column
 * @return JPanel The JPanel returned contains a JButton with an ActionListener. 
 */
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 
    this.row = row;
    this.column = column;
    this.table = table;
    button = (JButton) value;

    //prevent to add the action listener everytime the user click on the cell.
    if(button.getActionListeners().length == 0) button.addActionListener(this); 

    panel.add(button);
    panel.setBackground(table.getGridColor());
    return panel;
}

/**
 * Return a renderer for JButtons. The result is a button centered in the table's cell.
 * @return
 */
public static TableCellRenderer getRenderer() {
    return new TableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            JPanel panel = new JPanel(new GridBagLayout());
            panel.add((JButton) value);
            panel.setBackground(table.getGridColor());
            return panel;
        }
    };
}

}

}

And here is how to use it:

下面是如何使用它:

Demo.java

Demo.java

    table.setDefaultRenderer(JButton.class, ButtonEditor.getRenderer()); 
    table.setDefaultEditor(JButton.class, new ButtonEditor() {
        @Override
        public void actionPerformed(ActionEvent e) {

            //handle clicks here. for example:   
            if(column == 5) {
                System.out.Println(row);
                button.setFocusPainted(false);                  
            }
        }
    });