文章所有权归本人所有,如要用作商业用途请和我联系,如果要转贴,请注明出处和作者.
Powered BY G.T.M.
很高兴有时间写下自己开发的经历,又一次改变,从数据底层到了界面的GUI,一次又一次的挑战,我想,我在成长.
等我以后开发了新的东西或者解决新的问题,再写一遍血泪史,国庆的假期就为这个属性表给占了
不说太多,入正题:
用过JB的都知道JB的Design是个不错的界面,今次我参与的项目由于要出个Aplha版,所以要写类似IDE的GUI,我负责属性表和树.
原本实现一个JTable不难(虽然一开始走了一些弯路,去了搞JList),只要一边是属性名,一边是值就好了.事件响应或者拖拉那些都不是主要问题, 很容易就可以实现,但是要实现到能根据数据动态生成和根据具体属性值而有不同的表现和修改方式,倒有点麻烦,如果是在不同的Column还好,但是如果在同一个Cloumn就......
一开始,我就extends了 AbstractTableModel 写了一个内部类来实现JTable的建立(具体API请看看相关基础教程),为的就是以后好动态生成数据,由于数据的连接我可以定,所以我就定了用HashMap,属性名对属性值,以下是具体代码:
class MyTableModel extends AbstractTableModel {
HashMap data;
public void setData(HashMap hm, JTable table) {
data = hm;
/* while (j >= 0) {
type=array[j].getClass().toString();
if(type.equals("class java.util.Vector")){
contain=(Vector)array[j];
JComboBox comboBox = new JComboBox();
int i=contain.size()-1;
while(i>=0){
comboBox.addItem(contain.get(i--));
}
table.prepareEditor(new DefaultCellEditor(comboBox),j,1);
}
if(type.equals("class java.lang.Boolean")){
Boolean tf=(Boolean)array[j];
JCheckBox jcbox=new JCheckBox("",tf.booleanValue());
table.getCellEditor(j,1)= new DefaultCellEditor(jcbox),j,1);
}
j--;
}
table.updateUI();*/
/* table.setDefaultEditor(Vector.class,
new MyTableCellEditor());
table.setDefaultRenderer(Vector.class,
new MyComboBoxRenderer());*/
}
public int getColumnCount() {
return 2;
}
public int getRowCount() {
int rv = data.size();
return rv;
}
public String getColumnName(int col) {
return " ";//这个很有意思,没有这个“ “就没有常见的表头,大家可以把它取消然后看看效果
}
public Object getValueAt(int row, int col) {
if (col == 0) {
Object[] ol = data.keySet().toArray();//这里就是建立JTable每个Cell的具体方法和Set对应
return ol[row];
} else {
Object[] ol2 = data.values().toArray();
return ol2[row];
}
}
/*
* JTable uses this method to determine the default renderer/
* editor for each cell. If we didn't implement this method,
* then the last column would contain text ("true"/"false"),
* rather than a check box.
*/
/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
return col == 1;
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value, int row, int col) {
if (col == 1) {
Object[] ol = data.values().toArray();
ol[row] = value;
}
fireTableCellUpdated(row, col);
}
}
由于一开始的时候是从别人的例子上改的,所以给误导了,因为JTable本身就有自带默认的Editor像ComboBox和CheckBox等,一般可以通过在Model中用getColumnClass方法来获得.注意!!这里就是关键,也是消耗了我国庆假期的元凶!!如果在这个内部类中重写这个方法,将可以整行获得默认的Editor来改写,很方便,如下:
public void setUpSportColumn(JTable table,
TableColumn Column) {
//Set up the editor for the sport cells.
JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Knitting");
comboBox.addItem("Speed reading");
comboBox.addItem("Pool");
comboBox.addItem("None of the above");
Column.setCellEditor(new DefaultCellEditor(comboBox));
//Set up tool tips for the sport cells.
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
Column.setCellRenderer(renderer);
}
然后在刚才上面的内部类中添加一个getColunmClass的方法,返回是对应的某行某列的Class(注意,如果Model结构是Object[][]才可以,具体例子大家可以在互联网中找到)
但是不适合我们的需求,因为属性表只有2行,而且没列的表现都可能不同.
于是在JTable本身着手,就是他的 getCellEditor(int row, int column) ,这是我在反复单步调试而获得的最终结论,因为JTable的每个Cell的Renderer和Editor都需要定位,所谓的定位就是找出相应的Editor和Render,它内部实现是按照Column来获得的,也就是说,整个Column都用同一个Editor.这是个恶梦,当我发现的时候.然后我花了大量时间后发现它的prepareEditor(TableCellEditor editor, int row, int column) 和setDefaultEditor(Class columnClass, TableCellEditor editor) 后者是可以通过对象的Class来获得相应的Editor和Render的,但是在JTable中,关键就是getCellEditor(int row, int column)能不能正确返回某行某列的Class由于我用的HashMap(这样的用意除了键值对应还有就是当取出的对象是Vector的时候就自动封装一个JComboBox来修改).但是其实起getCellEditor(int row, int column)内部代码只用了column根本就没用到row!!
如果用Model的getColumnClass有不能获得row的参数,在不破坏封装的完整性的前提下,我还是选择了继承,把
getCellEditor(int row, int column)重写一遍
return getDefaultEditor(this.getModel().getValueAt(row,column).getClass());
然后在GUI中封装了自己Editor和Renderer,如:
public class MyComboBoxRenderer implements TableCellRenderer {
public MyComboBoxRenderer() {
}
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Vector vv = null;
if (value instanceof Vector) {
vv = (Vector) value;
JComboBox box = new JComboBox(vv);
if (isSelected) {
setForeground(table.getSelectionForeground());
box.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
// Select the current value
box.setSelectedItem(value);
return box;
}
return null;
}
}
还有Renderer
public class MyTableCellEditor extends AbstractCellEditor implements
TableCellEditor {
// This is the component that will handle the editing of the cell value
JComboBox box;
// This method is called when a cell value is edited by the user.
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int rowIndex, int vColIndex) {
// 'value' is value contained in the cell located at (rowIndex, vColIndex)
// JComboBox box=null;
Vector vv = null;
// if (value instanceof Vector) {
vv = (Vector) value;
box = new JComboBox(vv);
if (isSelected) {
setForeground(table.getSelectionForeground());
box.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
// Select the current value
box.setSelectedItem(value);
return box;
//}
// return null;
}
就能够根据如果某个cell里的是Vector就用JComboBox来修改,如果是Boolean就可以用CheckBox.其实最主要还是了解JTable的机制的问题.好了,说到这里问题就已经解决了,如果大家有问题请跟和我联络.