java之swing中Jtable的动态一列中的每行的Jcombobox显示不一样的数据

我们都知道JTable提供了columnModel可以设置指定的实现了TableCellEditor接口的控件但其实现时是整个列使用同一个cellEditor

例如combobox的celleditor就会导致整个列的combobox中的数据相同,这在条件选择时可以这样,但大多数时候我们需要每一行的combobox中的内容不一样

就是说思路上我们要指定每一样的不一样的combobox才可以实现

网上有教程什么在table中复写getCellEditor(int row, int column)然后指定行列为自定义的celleditor,虽然这样可以实现但对于每一行都要new一个combobox的celleditor这样肯定是不不可行的,

网上对于这种需求实现的例子很少,而且很多还是在骗分

今天就教大家如何实现这样的需求指定JTable的某列为JComboboxCellEditor并且每个Combobox可以显示不一样的数据

简单思路:

1、自定义单元编辑器(其中getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)需要通过先删除原有item在加载model对应单元中的原始数据)

2、自定义tablemodle,在tablemodel中定义好combobox列的数据为list或数组按需求写,并在tablemodel中设置一个方法返回此数据(这儿简单介绍一下在tablemodle中有一个getValueAt(int row, int column)它返回的是table显示的数据,就是说第一次某单元格是list数据它会返回一个list但如果有选择后他就返回选择后的值不会返回list,所以我们要自定义方法返回原始数据)

代码实现:

1、Jcombobxcelleditor

public class JComboboxCellEditor extends JComboBox<Object> implements TableCellEditor {

	// extends DefaultCellEditor
	protected EventListenerList listenerList = new EventListenerList();
	protected ChangeEvent changeEvent = new ChangeEvent(this);

	// 构造方法初始化事件监听器
	public JComboboxCellEditor() {
		addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				fireEditingStopped();
			}
		});
	}

	protected void fireEditingStopped() {
		CellEditorListener listener;
		Object[] listeners = listenerList.getListenerList();
		for (int i = 0; i < listeners.length; i++) {
			if (listeners[i] == CellEditorListener.class) {
				listener = (CellEditorListener) listeners[i + 1];
				listener.editingStopped(changeEvent);
			}
		}
	}

	protected void fireEditingCanceled() {
		CellEditorListener listener;
		Object[] listeners = listenerList.getListenerList();
		for (int i = 0; i < listeners.length; i++) {
			if (listeners[i] == CellEditorListener.class) {
				listener = (CellEditorListener) listeners[i + 1];
				listener.editingCanceled(changeEvent);
			}
		}
	}

	/**
	 * 添加单元格编辑监听
	 */
	@Override
	public void addCellEditorListener(CellEditorListener listener) {
		listenerList.add(CellEditorListener.class, listener);
	}

	/**
	 * 移除单元格编辑监听
	 */
	@Override
	public void removeCellEditorListener(CellEditorListener listener) {
		listenerList.remove(CellEditorListener.class, listener);
	}

	/**
	 * 取消编辑
	 */
	@Override
	public void cancelCellEditing() {
		fireEditingCanceled();
	}

	/**
	 * 停止编辑
	 */
	@Override
	public boolean stopCellEditing() {
		fireEditingStopped();
		return true;
	}

	/**
	 * 启用单元格编辑
	 */
	@Override
	public boolean isCellEditable(EventObject event) {
		return true;
	}

	/**
	 * 是否可以选择
	 */
	@Override
	public boolean shouldSelectCell(EventObject event) {
		return true;
	}

	/**
	 * 获取单元格选择的项
	 */
	@Override
	public Object getCellEditorValue() {
		return this.getSelectedItem();
	}

	/**
	 * 获取表中的编辑控件
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
//		if (isSelected) {
//			setForeground(table.getForeground());
//			super.setBackground(table.getBackground());
//		} else {
//			setForeground(table.getForeground());
//			setBackground(table.getBackground());
//		}
		Object object = ((JComboboxTableModel) table.getModel()).getOrigianlDataAt(row, column);
		if (object instanceof List) {
			this.removeAllItems();
			List<Object> list = (List<Object>) object;
			for (Object o : list) {
				this.addItem(o);
			}
		}
		return this;
	}

}

2、TableModel

public class JComboboxTableModel extends DefaultTableModel {

	// 原数据列表,这个是原始的数据
	List<List<Object>> data;
	// 列名
	private List<Object> columnNames;

	public List<Object> getColumnNames() {
		return columnNames;
	}

	/**
	 * 通过list类型数据构造tablemodel
	 * 
	 * @param data
	 * @param columnNames
	 */
	public JComboboxTableModel(List<List<Object>> data, List<Object> columnNames) {

		// 将list类型数据转化为Vector类型
		Vector<Vector<Object>> vectorData = FormatUtil.getVectorByTwoDimemsionalList(data);
		Vector<Object> vectorcolumnNames = FormatUtil.getVectorByOneDimensionalList(columnNames);

		// 设置table的DataVector
		setDataVector(vectorData, vectorcolumnNames);

		// 设置原数据
		this.data = data;
		this.columnNames = columnNames;
	}

	/**
	 * 通过array类型数据构造tablemodel
	 * 
	 * @param data
	 * @param columnNames
	 */
	public JComboboxTableModel(Object[][] data, Object[] columnNames) {
		super(data, columnNames);
		this.data = FormatUtil.getListByTwoDimensionalArray(data);
		this.columnNames = Arrays.asList(columnNames);
	}

	/**
	 * table通过这个方法获取模型数据
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		if (this.getDataVector() == null || this.getDataVector().size() == 0)
			return null;

		if (rowIndex >= this.getDataVector().size()) {
			throw new IndexOutOfBoundsException("The rowIndex is out of bounds. Your rowIndex is :" + rowIndex
					+ " , and the row size is :" + this.getDataVector().size());
		}

		List<Object> row = (List<Object>) this.getDataVector().get(rowIndex);

		if (row == null || row.size() == 0)
			return null;

		if (columnIndex >= row.size()) {
			throw new IndexOutOfBoundsException("The columnIndex is out of bounds. Your columnIndex is :" + columnIndex
					+ " , and the columns size is :" + row.size());
		}

		// 对list特殊处理
		// 如果某单元格中数据是list类型则显示list中的第一个数据
		// (当然这个在设计中只是针对数据第一次在table中显示和没有通过combobox进行选择的数据)
		if (row.get(columnIndex) instanceof List) {
			return ((List<Object>) row.get(columnIndex)).get(0);
		}

		return row.get(columnIndex);
	}

	/**
	 * combobox通过这个方法获取数据
	 * 
	 * @param rowIndex
	 * @param columnIndex
	 * @return
	 */
	public Object getOrigianlDataAt(int rowIndex, int columnIndex) {
		if (this.data == null || this.data.size() == 0)
			return null;

		if (rowIndex >= this.data.size()) {
			throw new IndexOutOfBoundsException("The rowIndex is out of bounds. Your rowIndex is :" + rowIndex
					+ " , and the row size is :" + this.data.size());
		}

		List<Object> row = (List<Object>) this.data.get(rowIndex);

		if (row == null || row.size() == 0)
			return null;

		if (columnIndex >= row.size()) {
			throw new IndexOutOfBoundsException("The columnIndex is out of bounds. Your columnIndex is :" + columnIndex
					+ " , and the columns size is :" + row.size());
		}

		return row.get(columnIndex);
	}

	/**
	 * 添加List类型的数据
	 * 
	 * @param data
	 */
	public void addRow(List<Object> data) {
		Vector<Object> rowData = FormatUtil.getVectorByOneDimensionalList(data);
		this.insertRow(this.getRowCount(), rowData);
		this.data.add(data);
	}

	/**
	 * 添加Array类型的数据
	 */
	@Override
	public void addRow(Object[] rowData) {
		super.addRow(rowData);
		this.data.add(Arrays.asList(rowData));
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void addRow(Vector rowData) {
		// TODO 暂时不会用到这种添加方式,有需求再改
		super.addRow(rowData);
	}

}

3、JTable中的数据考虑到线程安全使用个的是Vector这作者写了个转化工具这也提供出来了(供给大家参考)

public class FormatUtil {

	/**
	 * 二维数组转化为List
	 * 
	 * @author JiangGengchao
	 * @param a
	 * @return
	 */
	public static <T> List<List<T>> getListByTwoDimensionalArray(T[][] a) {
		List<List<T>> list1 = new ArrayList<List<T>>();
		for (int i = 0; i < a.length; i++) {
			List<T> list2 = new ArrayList<T>();
			for (int j = 0; j < a[i].length; j++) {
				list2.add(a[i][j]);
			}
			list1.add(list2);
		}
		return list1;

	}

	/**
	 * 二维List转化为Vector
	 * 
	 * @param list
	 * @return
	 */
	public static <T> Vector<Vector<T>> getVectorByTwoDimemsionalList(List<List<T>> list) {
		Vector<Vector<T>> vector1 = new Vector<Vector<T>>();
		Iterator<List<T>> iterator1 = list.iterator();
		while (iterator1.hasNext()) {
			Iterator<T> iterator2 = iterator1.next().iterator();
			Vector<T> vector2 = new Vector<T>();
			while (iterator2.hasNext()) {
				vector2.add(iterator2.next());
			}
			vector1.add(vector2);
		}
		return vector1;
	}

	/**
	 * 一维List转化为一维Vector
	 * 
	 * @param list
	 * @return
	 */
	public static <T> Vector<T> getVectorByOneDimensionalList(List<T> list) {
		Vector<T> vector = new Vector<T>();
		Iterator<T> iterator = list.iterator();
		while (iterator.hasNext()) {
			vector.add(iterator.next());
		}
		return vector;
	}
}

4、简单JTable封装

public class JIrmComboboxTable extends JTable {

	/**
	 * 暂时还需要手动设置列模型的cellEditor,后期可以改成动态识别list然后自动设置
	 * 
	 * @param column
	 */
	public void setCellRendererAndEditor(int column) {
		this.getColumnModel().getColumn(column).setCellEditor(new JComboboxCellEditor());
	}

	// 坑爹设置了model后table就不调用这个方法获取cellEditor了
	@Override
	public TableCellEditor getCellEditor(int row, int column) {
		return super.getCellEditor(row, column);
	}

	public void addRow(List<Object> items) {
		// TODO 这个功能在model中提供了,这儿暂时不做提供
	}
}

3、测试:

public class MyComponentTest extends JFrame {

	public MyComponentTest() {

		this.setTitle("MyComponentTest");
		this.setSize(500, 400);
		this.setLocationRelativeTo(null);
		this.getContentPane().setLayout(new BorderLayout());
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
				| UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);

		initUI3();

		this.setVisible(true);
	}

	/**
	 * 时间段控件
	 */
	private void initUI1() {
		JPeriodTimePicker periodTimePicker = new JPeriodTimePicker();
		this.add(periodTimePicker);
	}

	/**
	 * 数字段控件
	 */
	private void initUI2() {
		JPeriodNumberField periodNumberField = new JPeriodNumberField(64, 32, -Double.MAX_VALUE, Double.MAX_VALUE);
		this.add(periodNumberField);
	}

	/**
	 * combobox的table
	 */
	private void initUI3() {

		List<Object> templist1 = new ArrayList<Object>();
		templist1.add("list11");
		templist1.add("list12");

		List<Object> templist2 = new ArrayList<Object>();
		templist2.add("list21");
		templist2.add("list22");
		templist2.add("list23");

		List<Object> columnNames = new ArrayList<Object>();
		columnNames.add("c21");
		columnNames.add("c22");
		columnNames.add("list");

		List<Object> r1 = new ArrayList<Object>();
		r1.add("c11");
		r1.add("c12");
		r1.add(templist1);

		List<Object> r2 = new ArrayList<Object>();
		r2.add("c21");
		r2.add("c22");
		r2.add(templist2);

		List<List<Object>> data = new ArrayList<List<Object>>();
		data.add(r1);
		data.add(r2);

		// Object[][] data = { { "test11", "test12", templist1 }, { "test21",
		// "test22", templist2 } };
		// Object[] columnNames = { "c1", "c2", "list" };

		model = new JComboboxTableModel(data, columnNames);
		JIrmComboboxTable table = new JIrmComboboxTable();
		table.setRowHeight(24);
		table.setModel(model);
		table.setCellRendererAndEditor(2);

		// JTable table = new JTable(3,3){
		// @Override
		// public TableCellEditor getCellEditor(int row, int column) {
		// if(row == 2 && column == 2) {
		// ComboBoxCellEditor cellEditor = new ComboBoxCellEditor();
		// cellEditor.addItem("12");
		// cellEditor.addItem("34");
		// return cellEditor;
		// }
		// return super.getCellEditor(row, column);
		// }
		// };
		// table.setRowHeight(30);
		JScrollPane sp = new JScrollPane(table);

		JButton addOneRowData = new JButton(addDataAction);
		
		this.add(sp, BorderLayout.CENTER);
		this.add(addOneRowData, BorderLayout.SOUTH);

	}

	private JComboboxTableModel model;
	
	/**
	 * 动态添加一行数据
	 * @author JiangGengchao
	 * @date 2016年4月14日
	 */
	private MAction addDataAction = new MAction("动态添加数据") {
		@Override
		public void execute(ActionEvent e) {
			List<Object> newColumnList = new ArrayList<Object>();
			newColumnList.add("ncl1");
			newColumnList.add("ncl2");
			
			List<Object> newRowList = new ArrayList<Object>();
			newRowList.add("new1");
			newRowList.add("new2");
			newRowList.add(newColumnList);
			
			model.addRow(newRowList);
		}
	};

	public static void main(String[] args) {
		new MyComponentTest();
	}

}
笔者只是在这儿记录备忘的,希望能帮助到看客






  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值