6

我希望能够在一个带有 JButton 的单元格中拥有一个 JPanel,该 JButton 在单击时会起作用。

我查找了有关单元格编辑器的操作指南,但所有示例都讨论了用另一个组件替换单元格(例如用 JTextField 替换一个 int 等)。我的情况有点不同:

我有以下 ADT

class MyClass {
  public String title;
  public String url;
  public String path;
  public int annotations;
}

我创建了一个具有 1 列的自定义表格单元模型,该列的类是 MyClass。然后我为该类创建了一个单元格渲染器,它返回一个 JPanel,如下所示:

MyClass 单元格渲染器

如您所见,JPanel 包含一个按钮。我希望此按钮在单击时启动 JFrame。有任何想法吗?

如果您建议 Cell Editor,请更具体地说明如何操作。如果可能,提供一些伪代码。

谢谢你。

PS我很确定这个问题的标题需要一些工作。;)

4

3 回答 3

9

coding.mof的回复之后,我终于做到了我想要的。但是,我想为这个问题提供一个更完整的答案,所以我会自己提供一个。

因此,Cell Renderers 只是简单地绘制组件,不允许在其中进行任何交互。而单元格编辑器则可以。

最初,JTable 中的所有单元格都是由注册的渲染器返回的组件。However, when a cell is selected, this component is replaced by a component that is returned by the editor. 这两个实际上可以是不同的组件!我很确定您可以利用这一点并制作一些时髦的细胞:P

无论如何,在本例中,渲染器和编辑器都显示相同的组件,因此我们将创建一个供双方使用的组件。

首先,我们需要创建一个返回 ADT 的 TableModel:

class MyClassTableModel extends DefaultTableModel {
  List<MyClass> data;

  public MyClassTableModel(List<MyClass> data) {
    this.data = data;
  }

  public Class<?> getColumnClass(int columnIndex) { return MyClass.class; }
  public int getColumnCount() { return 1; }
  public String getColumnName(int columnIndex) { return "MyClass"; }
  public int getRowCount() { return (data == null) ? 0 : data.size(); }
  public Object getValueAt(int rowIndex, int columnIndex) { return data.get(rowIndex); }
  public boolean isCellEditable(int rowIndex, int columnIndex) { return true; }
}

现在,我们创建一个将在渲染器和编辑器之间共享的组件:

class MyClassCellComponent extends JPanel() {
  MyClass myClass;

  public MyClassCellComponent() {
    // initialize components (labels, buttons, etc.)
    // add action listeners
  }

  public void updateData(MyClass myClass, boolean isSelected, JTable table) {
    this.myClass = myClass;
    // update buttons, labels etc. accordingly
  }
}

isSelected 和 table 参数用于渲染面板的背景,是可选的。下面是渲染器如何使用我们的组件:

class MyClassCellRenderer implements TableCellRenderer {
  MyClassCellComponent panel;

  public MyClassCellRenderer() {
    panel = new MyClassCellComponent();
  }

  public Component getTableCellRendererComponent(JTable table, Object value,        boolean isSelected, boolean hasFocus, int row, int column) {
    MyClass myClass = (MyClass)value;
    panel.updateData(myClass, isSelected, table);
    return panel;
  }
}

以下是编辑器的使用方式:

class MyClassCellEditor extends AbstractCellEditor {
  MyClassCellComponent panel;
  public MyClassCellEditor() {
    panel = new MyClassCellComponent();
  }
  public Component getTableCellEditorComponent(JTable table, Object value,      boolean isSelected, int row, int column) {
    MyClass myClass = (MyClass)value;
    panel.updateData(myClass, true, table);
    return panel;
  }
  public Object getCellEditorValue() {
    return null;
  }
}

就这样。现在我们可以简单地创建一个 JTable,如下所示:

JTable myClassTable = new JTable(new MyClassTableModel());
myClassTable.setDefaultRenderer(MyClass.class, new MyClassCellRenderer());
myClassTable.setDefaultEditor(MyClass.class, new MyClassCellEditor());

我们完成了!

PS 我很确定我们可以将渲染器和编辑器组合成一个类,扩展 AbstractCellEditor 并实现 TableCellRenderer,但我不确定性能。

于 2010-08-31T08:45:47.233 回答
5
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor { 

JComponent pan = new JPanel();

public MyTableCellEditor () {
  pan.add(btn);
  // add all elments you need to your panel
  btn.addActionListener( /* the listener which will handle the events */ );
}

public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex) { 
   btn.setText( /* according to row or whatever*/ );
   // set all elemnts of you panel to the according values
   // or add dynamically an action listener
   return pan;
}
public Object getCellEditorValue() { return new Void(); } 
} 

因此,在您的侦听器中,您必须检查表的选择,以便您可以以不同的方式对每一行做出响应。如果要将所有元素保留在一列中,可以将 JButton 替换为包含所有组件的面板。然后 JTable 会将所有事件转发到该 JPanel。

于 2010-08-31T07:32:25.830 回答
0

您可以创建一个包含多列的表,然后您可以添加一个单独的列来包含您的按钮。Table Button Column类允许您轻松完成此操作。

于 2010-08-31T15:27:32.770 回答