【问题标题】:Making a JButton clickable inside a JTable在 JTable 中使 JButton 可点击
【发布时间】:2021-10-03 13:31:48
【问题描述】:

这是我想做的截图:

那里发生的事情是 JButton 正确显示,但是当我单击它时没有任何反应。 经过一番搜索,我发现table.getValueAt()返回的Object是String而不是JButton...

代码如下:

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

我使用它在运行时填充 JTable : (tblResult 现在是Clients.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));
    }}  
); 

这里是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;
    }


}

最后,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();
          }

        }
      }
    }

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

提前致谢!

【问题讨论】:

  • value.getClass() ?它还返回“java.lang.String”
  • CellRenderer 仅用于“绘制”表格,并未设置为“实时组件”。 getValueAt 返回 TableModel 的值,而不是组件,因此它可能会返回“Consulter”
  • 我就是这么想的。但是,有没有办法解决它?

标签: java swing jtable jbutton


【解决方案1】:

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

有一种方法可以让您单击按钮,并且仍然保持您的表格不可编辑,但这与正确的代码相去甚远。只是一个可能的解决方案的简要概述(我现在没有时间给出完整的代码示例)

  • 将鼠标侦听器附加到表格
  • 当您收到鼠标点击时,确定发生鼠标点击的单元格
  • 向表格渲染器询问该单元格的组件
  • 使用鼠标单击的位置来确定按钮是否存在于上一步的组件中的特定位置
  • 如果是这样,请通过按钮 api 进行点击(doClick 方法)

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

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

正如其他答案中指出的那样,最简单的方法是只使那一列可编辑并使用编辑器

【讨论】:

  • 感谢您的宝贵时间。好吧,它没有预期的那么性感,但它可能是一个解决方案。
  • 如果我周末有时间,我可能会尝试添加一些代码。我知道上面的解决方案适用于JTree,因为我在那里使用它
【解决方案2】:

来自 Rob Camick 的 Table Button Column 可能满足您的需求。

【讨论】:

    【解决方案3】:

    本文提供了一种更简单的方法来解决您的问题,而无需添加 MouseListener 并计算点击是否实际在按钮上:

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

    【讨论】:

      【解决方案4】:

      试试这个:

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

      【讨论】:

        【解决方案5】:

        重载您的 Table 模型,并为带有按钮的单元格设置 isCellEditable(int, int) return false。

        在将 MouseListener 添加到表中时效果很好。

        【讨论】:

          【解决方案6】:

          这是我的解决方案

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

          }

          这里是如何使用它:

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

          【讨论】:

            猜你喜欢
            • 2011-07-30
            • 2023-03-20
            • 2011-08-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多