问题背景:
项目中要实现自己的JTable的CellEditor,easy!参考官方例子代码,也就是extends AbstractCellEditor重写里面的getTableCellEditorComponent的方法,可是问题来了,实现了自己的cellEditor,但是其行为为只要点击cell,马上就cell就处于编辑状态,如何实现像默认的情况下,双击启动编辑模式呢?
解决办法:
也许处于惯性思维方式下,想都没有想,便F3到了DefaultCellEditor源码,便开始寻找原始解决方案!
/** * An integer specifying the number of clicks needed to start editing. * Even if <code>clickCountToStart</code> is defined as zero, it * will not initiate until a click occurs. */ protected int clickCountToStart = 1;
看到这条语句,心中窃喜,用大腿想都想得到,它就是控制点击次数,从而控制编译器启动的.
public DefaultCellEditor(final JTextField textField) { editorComponent = textField; this.clickCountToStart = 2; delegate = new EditorDelegate() { public void setValue(Object value) { textField.setText((value != null) ? value.toString() : ""); } public Object getCellEditorValue() { return textField.getText(); } }; textField.addActionListener(delegate); }
这个类构造器让我迷惑了好久,原来它里面还有个内部类,这看起来就很复杂了!
习惯了过程化编程思维方式的我,看到这句余音缭绕,弯弯曲曲的语句,会本能的放弃,纵使它实际是很简单,很优雅!
放弃之后我选择了去寻找别的解决方式,google了,在尝试了别的比如有一条无所不能的语句,就可以达到目的的,或者
就万能的语句,最终还是硬着头皮看它是怎么实现的.
这次好像有点感觉了
protected EditorDelegate delegate;
delegate的重复出现,让我好像想到了什么,对了,就是代理,难道这么个短小的几行和一个类,还用了代理模式?
不用怀疑了,它确实用了代理模式!
看了N多设计模式书的我,觉得那就更应该欣赏下这些代码了,而且我的观点一直是:设计模式,不仅让代码质量提高,而且
理解起来更容易的
那它代理了谁呢?这个问题确实让我困惑了很长时间
protected class EditorDelegate implements ActionListener, ItemListener, Serializable { /** The value of this cell. */ protected Object value; /** * Returns the value of this cell. * @return the value of this cell */ public Object getCellEditorValue() { return value; } /** * Sets the value of this cell. * @param value the new value of this cell */ public void setValue(Object value) { this.value = value; } /** * Returns true if <code>anEvent</code> is <b>not</b> a * <code>MouseEvent</code>. Otherwise, it returns true * if the necessary number of clicks have occurred, and * returns false otherwise. * * @param anEvent the event * @return true if cell is ready for editing, false otherwise * @see #setClickCountToStart * @see #shouldSelectCell */ public boolean isCellEditable(EventObject anEvent) { if (anEvent instanceof MouseEvent) { return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart; } return true; } /** * Returns true to indicate that the editing cell may * be selected. * * @param anEvent the event * @return true * @see #isCellEditable */ public boolean shouldSelectCell(EventObject anEvent) { return true; } /** * Returns true to indicate that editing has begun. * * @param anEvent the event */ public boolean startCellEditing(EventObject anEvent) { return true; } /** * Stops editing and * returns true to indicate that editing has stopped. * This method calls <code>fireEditingStopped</code>. * * @return true */ public boolean stopCellEditing() { fireEditingStopped(); return true; } /** * Cancels editing. This method calls <code>fireEditingCanceled</code>. */ public void cancelCellEditing() { fireEditingCanceled(); } /** * When an action is performed, editing is ended. * @param e the action event * @see #stopCellEditing */ public void actionPerformed(ActionEvent e) { DefaultCellEditor.this.stopCellEditing(); } /** * When an item's state changes, editing is ended. * @param e the action event * @see #stopCellEditing */ public void itemStateChanged(ItemEvent e) { DefaultCellEditor.this.stopCellEditing(); } }
里面实现的接口都是一般的公共的接口,至少不是那种玩具代码一样,一看就看出了代理谁了?
返回前面看,我最初的想法是代理的是JTextField这种可以编辑的组件,这也好像瞒合理的,编辑器嘛,就是那些可以让你可以编辑的组件!
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { delegate.setValue(value); return editorComponent; }
观察这个方法,可以很快的否定上面的假设.代理对象在这里并没有真正的去代理可编辑的组件
这个时候让我犯难了,在前后看看AbstractCellEditor,实在想不出端倪!
/** * The delegate class which handles all methods sent from the * <code>CellEditor</code>. */
突然间看到了这句话,它很快的告诉了delegate的意图,原来代理对象是处理cellEdtor的一些接口!
总结:
没有对象思维方式,去探寻基于像java这种面向对象语言,尤其是其源代码,会让你觉得无路可走!
其实解决这个问题的方式,应该先去弄明白CellEditor这样的接口,看里面封装了些什么行为!
问题的最终解决是,复写一些CellEditor里面的行为,就可以很快的实现了
/** * Returns true if <code>anEvent</code> is <b>not</b> a * <code>MouseEvent</code>. Otherwise, it returns true * if the necessary number of clicks have occurred, and * returns false otherwise. * * @param anEvent the event * @return true if cell is ready for editing, false otherwise * @see #setClickCountToStart * @see #shouldSelectCell */ public boolean isCellEditable(EventObject anEvent) { if (anEvent instanceof MouseEvent) { return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart; } return true; }
或者直接把上面的代码拷过去,就ok了!
由解决问题方法想到的,自己在面向对象方面,尤其是思维层次上,还是一个弱项!