KTable采用的是适配器模式,因为就表现形式来说,KTable采用的是表格方式展现数据,样式基本固定,而数据来源则千差万别:List、HashMap、XML文件、数据库等等,因此采用适配器模式,在数据来源和表现形式之间架起一座桥梁,使得数据可以正确的显示出来。
对于KTable的创建则十分简单,两行代码,则可以完成。
// put a table in tabItem3...
final KTable table4 = new KTable(comp4, SWT.FULL_SELECTION | SWTX.AUTO_SCROLL | SWTX.FILL_WITH_LASTCOL);
table4.setModel(new TownExampleModel());
而真正关键的,涉及整个表格的观,数据等,则都在Model中。
此为自定义的Model类,继承自KTableNoScrollModel。(而KTableNoScrollModel有一个好处是可以自适应width,即如果界面最大化,或者resize,相关的表格可以自适应加宽)。
合并单元格逻辑(doBelongsToCell):
00
|
01
|
02
|
03
|
04
|
05
|
06
|
10
|
11
|
12
|
13
|
14
|
15
|
16
|
20 |
21
|
22
|
23
|
24
|
25
|
26
|
30
|
31
|
32
|
33
|
34
|
35
|
36
|
40
|
41
|
42
|
43
|
44
|
45
|
46
|
50
|
51
|
52
|
53
|
54
|
55
|
56
|
则需要在doBelongsToCell中定义合并逻辑。
public Point doBelongsToCell(int col, int row) {
if (isFixedCell(col, row)) {
System.out.println(col+"-"+row);
return new Point(col, row);
}
System.out.println(getFixedColumnCount()+":"+getFixedSelectableColumnCount());
col-=getFixedHeaderColumnCount()+getFixedSelectableColumnCount();
row-=getFixedHeaderRowCount()+getFixedSelectableRowCount();
if ((col==1 && row==1) && (col%2==0 && row%2==0))
return new Point(col, row);
// find supercell to merge with:
int newCol = col;
int newRow = row;
if (col%2!=0)
newCol--;
if (row%2!=0)
newRow--;
return new Point(newCol+getFixedHeaderColumnCount()+getFixedSelectableColumnCount(), newRow+getFixedHeaderRowCount()+getFixedSelectableRowCount());
}
而得知上面的逻辑,则可以简单的写出合并相邻两列算法:
public Point doBelongsToCell(int col, int row) {
if (isFixedCell(col, row)) {
return new Point(col, row);
}
if(col==0){
return new Point(col,row);
}
if(row==0){
return new Point(col,row);
}
if(col%2==0){
return new Point(col-1,row);
}
return new Point(col,row);
}
getCellEditor即返回对应单元格的编辑器,有:
采用editor则可以对单元格的数据进行编辑设计。但需要注意的是:
采用的editor与对应的content也是有关系的,例如本例中,使用KTableCellEditorCheckbox2,则对应的content则需要为Boolean类型对象。
doGetContentAt返回的是单元格中数据内容。对于此方法有一个通用的方法,
public Object doGetContentAt(int col, int row) {
//System.out.println("col "+col+" row "+row);
Boolean val = (Boolean ) content.get(col + "/" + row);
if (val != null)
return val;
if ((col+row)%2==1)
val = new Boolean(true);
else
val = new Boolean(false);
content.put(col+"/"+row, val);
return val;
}
利用了content.get()方法,取出其中对应行列的数据,然后为其它的设置默认值,也可以不设置值,在每次对单元格数据进行修改则会自动调用doGetContentAt方法,所以对就数据的维护则在content中。
private HashMap content = new HashMap();
doGetCellRenderer()方法返回的是对应单元格的外观器。
以上是默认的一些样式器。当然也可以继承,以实现自定义的样式器,从而对单元格的样式进行自定义的美化。
一个核心的需要重载的方法则是
public void drawCell(GC gc, Rectangle rect, int col, int row,
Object content, boolean focus, boolean fixed, boolean clicked,
KTableModel model)
通过col,row对相应的单元格做自己的设计,一般包括边框,填充内容,(颜色,大小 ,线型),而且利用focus参数,可以进行获得焦点的设计。如下所示:
case TypeConstant.CellType.FieldCell: {
Display m_Display = Display.getCurrent();
if (focus && (m_Style & 16) != 0) {
rect = drawDefaultSolidCellLine(gc, rect, COLOR_LINE_LIGHTGRAY,
COLOR_LINE_LIGHTGRAY);
/** 在这设置点击选中颜色 */
drawCellContent(gc, rect, content.toString(), null,
m_Display.getSystemColor(5),
TypeConstant.ColorDefind.CELLFOUCS);
gc.drawFocus(rect.x, rect.y, rect.width, rect.height);
} else {
drawDefaultSolidCellLine(gc, rect, COLOR_BGFOCUS, COLOR_BGFOCUS);
drawCellContent(gc, rect, content.toString(), null,
getForeground(), TypeConstant.ColorDefind.COLOR_FIELDCELL);
isFocus = true;
}
if ((m_Style & 128) != 0)
drawCommentSign(gc, rect);
break;
}
}
在ktable中:
/** 绘制外框 */
protected void drawBottomSpace(GC gc) {
super.drawBottomSpace(gc);
Rectangle clientArea = getClientArea();
if (m_Model.getRowCount() > 0) {
if ((getStyle() & 8388608) == 0)
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_WHITE));
else
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_WHITE));
/** 左竖直线 */
gc.drawLine(0, 0, 0, (clientArea.y + clientArea.height) - 1);
/** 上水平线 */
gc.drawLine(0, 0, clientArea.x + clientArea.width, 0);
/** 右竖直线 */
gc.drawLine((clientArea.x + clientArea.width) - 1, 0,
(clientArea.x + clientArea.width) - 1,
(clientArea.y + clientArea.height) - 1);
/** 下水平线 */
gc.drawLine(0, (clientArea.y + clientArea.height) - 1,
(clientArea.x + clientArea.width) - 1,
(clientArea.y + clientArea.height) - 1);
// if(m_LeftColumn + m_ColumnsVisible == m_Model.getColumnCount())
// gc.drawLine((clientArea.x + clientArea.width) - 1, 0,
// (clientArea.x + clientArea.width) - 1, clientArea.y +
// clientArea.height);
}
}
而不管是对于ktable增加自定义的menuAction或者是相应的监听器,都需要在setModel进行绑定。
public void setModel(KTableModel model) {
super.setModel(model);
this.m_Model=model;
/**在此定义加入menu*/
hookContextMenu();
hookListener();
}
而对于上下文菜单的绑定,和监听器的绑定,如下:
private void hookListener() {
addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
System.out.println("mouseclick");
}
public void mouseDown(MouseEvent mouseevent) {
System.out.println("mousedown");
}
public void mouseUp(MouseEvent mouseevent) {
System.out.println("mouseup");
}
});
}
/** 设置menu */
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
System.out.println("xh");
fillContextMenu(manager);
}
});
org.eclipse.swt.widgets.Menu menu = menuMgr.createContextMenu(this);
setMenu(menu);
}
这只是设置了menu且类型是popupMenu。
private void fillContextMenu(IMenuManager manager) {
manager.add(newFieldManager);
manager.add(insertAction);
manager.add(removeAction);
manager.add(new Separator());
manager.add(cutAction);
manager.add(pasteAction);
}
而显示哪些action,则是根据一些规则来判断,一般是由单元格本身的属性,如:
/** cell获得焦点 */
public void focusCell(int col, int row, int stateMask) {
super.focusCell(col, row, stateMask);
/** 根据cell的类型,设置action的enable值 */
if(((FieldTableModel)m_Model).getCellType(col, row)==TypeConstant.CellType.FieldCell)
{
insertAction.setEnabled(true);
newFieldManager.setVisible(true);
removeAction.setEnabled(false);
cutAction.setEnabled(false);
}else
{
insertAction.setEnabled(false);
newFieldManager.setVisible(false);
removeAction.setEnabled(false);
cutAction.setEnabled(false);
}
/*if (model.getCellType(col, row) == TypeConstant.CellState.CELLSELECT) {
insertAction.setEnabled(true);
newFieldManager.setVisible(true);
removeAction.setEnabled(false);
cutAction.setEnabled(false);
}*/
}
最终可以设计表格如下: