学习定制表格树的项(一)

原文:http://www.eclipse.org/articles/article.php?file=Article-CustomDrawingTableAndTreeItems/index.html

本来将原来那篇拷贝过来,想写一些注释的,但太大了,太慢了,还是另写吧:

  总述

1,为什么要定制去画呢?

因为原来的Item有自己的局限性: For example, an item in a table or tree can only contain one image, and it must appear before its text. Item的一个单元只能支持一个图像,而且只能默认画在字符串的前面。

 

2,在定制Item的时候,是基于Cell来画制的,什么是Cell,如果一个Table有2列3行,那么它就有6个Cell。

 

3,定制Item是由三个事件完成的,SWT.MeasureItem,SWT.EraseItem和SWT.PaintItem。

· SWT.MeasureItem: allows a client to specify the dimensions of a cell's content【长宽】

· SWT.EraseItem: allows a client to custom draw a cell's background and/or selection, and to influence whether the cell's foreground should be drawn【背景、选择时的处理、是否画默认的前景】

· SWT.PaintItem: allows a client to custom draw or augment a cell's foreground and/or focus rectangle【自己画或者增加前景】

 1, SWT.MeasureItem

1,SWT.MeasureItem是第一调用的用户定制事件。

2,SWT.MeasureItem中控制的content size而不是cell size,因为cell size包括了额外的装饰如checkboxes or tree indentation

SWT.MeasureItem事件预定的变量:

· item: the item

· index: the column index of item to be measured

· width: the default content width that the table would use if it were to draw the cell itself, based on its text, image, and checkbox

· height: the default content height that the table would use, based on the height of all of its items

· gc: a GC that is configured with the cell's font, which can be useful for performing string measurements

 

 3,例子

  

public class Snippet271 {

public static void main(String[] args) {

Display display = new Display();

Shell shell = new Shell(display);

shell.setBounds(10,10,150,150);

shell.setLayout(new FillLayout());

 

Table table = new Table(shell, SWT.NONE);

table.setLinesVisible(true);

for (int i = 0; i<3; i++) {

new TableItem(table, SWT.NONE).setText("item " + i);

}

table.addListener(SWT.MeasureItemnew Listener() {

public void handleEvent(Event event) {

event.height = event.gc.getFontMetrics().getHeight() * 2;

event.width *=  2;

}

});

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

display.dispose();

}

}

 


 

 

 

 程序中设置了Item的高度为gc字体高度的两倍,宽度为本来宽度的两倍。

  



 

这个是不改变Item高和宽的情况。

4,利用SWT.MeasureItem 改变Item的宽和高的有如下的限制:

a,现在宽和高时不可以缩小到比默认的小的,只能放大,不能缩小。

b,所有的Item在一个表格或一个Tree中,只有一个大小的高,增大一个,增大所有。

c,对于已经设置了宽度的column,SWT.MeasureItem 不起作用,在column调用Pack的时候,起作用。

例子:

 

public class Snippet272 {

public static void main(String[] args) {

Display display = new Display(); 

Shell shell = new Shell(display);

shell.setBounds(10,10,400,200);

Table table = new Table(shell, SWT.NONE);

table.setBounds(10,10,350,150);

table.setHeaderVisible(true);

table.setLinesVisible(true);

final TableColumn column0 = new TableColumn(table, SWT.NONE);

column0.setWidth(100); column0.setText("col1");

final TableColumn column1 = new TableColumn(table, SWT.NONE);

column1.setWidth(100); column1.setText("col2");

column0.addListener(SWT.Selectionnew Listener() {

public void handleEvent(Event event) {

column0.pack();

}

});

for (int i = 0; i < 5; i++) {

TableItem item = new TableItem(table, SWT.NONE);

item.setText(0, "item " + i + " col 0");

item.setText(1, "item " + i + " col 1");

}

table.addListener(SWT.MeasureItemnew Listener() {

public void handleEvent(Event event) {

event.width *= 2;

}

});

 

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

display.dispose();

}

}

 

 

 


 
  

col1只用在点击时调用column0.pack(),SWT.MeasureItem中定义的宽带加倍才起作用。

 

2,SWT.EraseItem 

SWT.EraseItem是被调用的第二个事件,这个事件是在画背景前调用。背景包括背景和选择背景,这个事件允许用户画背景和选择背景。

该事件的预定义的变量:

· item: the item【事件的源】

· index: the column index of item being drawn

· xy: the table-relative co-ordinates of the top-left corner of the cell

· widthheight: the width and height of the full cellor the content width of the cell if the table has no columnsif these values were previously set by an SWT.MeasureItem listener then they are the same here 

· gc: the GC configured with the default foreground, background, font and clipping for the cell

detail: the logical OR of one or more of the following bits, indicating what will be drawn by default: 

 

· SWT.FOREGROUNDthis bit will be set if the default cell foreground will be drawn once the background has been drawn (default is true)【我将这里理解为要不要完全由自己来画】

· SWT.BACKGROUND: this bit will be set if either a cell-specific or item-specific background color will be drawn for this cell (ie.- a color has previously been set with either TableItem.setBackground(Color) or TableItem.setBackground(int, Color))

· SWT.SELECTED: this bit will be set if the selection will be drawn for this cell, implying that this item is selected

· SWT.FOCUSED: this bit will be set if the focus rectangle will be drawn for this cell, implying that this item is the focus item in the table

· SWT.HOT(@since 3.3) this bit will be set if the mouse hover background will be drawn for this cell (not all platforms draw this)

 

doit: this boolean indicates whether the table will do the drawing specified in the detail field once this listener has completed (default is true)

 

 例子:

 

public class Example3 {

public static void main(String[] args) {

Display display = new Display(); 

Shell shell = new Shell(display);

final Color red = display.getSystemColor(SWT.COLOR_RED);

final Color yellow = display.getSystemColor(SWT.COLOR_YELLOW);

final Table table = new Table(shell, SWT.FULL_SELECTION);

table.setHeaderVisible(true);

new TableColumn(table, SWT.NONE).setWidth(100);

new TableColumn(table, SWT.NONE).setWidth(100);

new TableColumn(table, SWT.NONE).setWidth(100);

for (int i = 0; i < 5; i++) {

TableItem item = new TableItem(table, SWT.NONE);

item.setText(0, "item " + i + " col 0");

item.setText(1, "item " + i + " col 1");

item.setText(2, "item " + i + " col 2");

}

table.addListener(SWT.EraseItemnew Listener() {

public void handleEvent(Event event) {

event.detail &= ~SWT.HOT;

if ((event.detail & SWT.SELECTED) == 0) return/* item not selected */

int clientWidth = table.getClientArea().width;

GC gc = event.gc;

Color oldForeground = gc.getForeground();

Color oldBackground = gc.getBackground();

gc.setForeground(red);

gc.setBackground(yellow);

gc.fillGradientRectangle(event.x, event.y, event.width, event.heightfalse);

gc.setForeground(oldForeground);

gc.setBackground(oldBackground);

event.detail &= ~SWT.SELECTED;

}

});

 

table.pack();

shell.pack();

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

display.dispose();

}

}

 

 

 

 实现了选择的在Item中,画上一个渐变的背景色。

这里要注意:

a,不能用event.detail==SWT.SELECTED的方法来判断有没有被选择上,这里detail可能好多位有效。

b,处理完最好要取消SWT.SELECTED事件,event.detail &= ~SWT.SELECTED取消,要不然默认的处理SELECTED的事件还是要被调用。

c,这里的gc.fillGradientRectangle(0, event.y, clientWidth, event.height, false);坐标用的0和clientWidth,如果用gc.fillGradientRectangle(event.x, event.y, event.width, event.height, false);就成了下图的效果,想想就知道了,EraseItem事件是针对每一个cell,这样就是三个独立的cell画了三次,实际上上面也是画了三次,只不过都是重复了。




 
 

 

再一个画背景的例子:

 

public class Snippet273 {

public static void main(String[] args) {

final String[] MONTHS = {

"Jan""Feb""Mar""Apr""May""Jun",

"Jul""Aug""Sep""Oct""Nov""Dec"

};

final int[] HIGHS = {-7, -4, 1, 11, 18, 24, 26, 25, 20, 13, 5, -4};

final int[] LOWS = {-15, -13, -7, 1, 7, 13, 15, 14, 10, 4, -2, -11};

final int SCALE_MIN = -30; final int SCALE_MAX = 30;

final int SCALE_RANGE = Math.abs(SCALE_MIN - SCALE_MAX);

 

Display display = new Display();

Shell shell = new Shell(display);

shell.setBounds(10,10,400,350);

shell.setText("Ottawa Average Daily Temperature Ranges");

final Color blue = display.getSystemColor(SWT.COLOR_BLUE);

final Color white = display.getSystemColor(SWT.COLOR_WHITE);

final Color red = display.getSystemColor(SWT.COLOR_RED);

// final Image parliamentImage = new Image(display, "./parliament.jpg");

final Table table = new Table(shell, SWT.NONE);

table.setHeaderVisible(true);

table.setLinesVisible(true);

table.setBounds(10,10,350,300);

// table.setBackgroundImage(parliamentImage);

for (int i = 0; i < 12; i++) {

TableItem item = new TableItem(table, SWT.NONE);

item.setText(MONTHS[i] + " (" + LOWS[i] + "C..." + HIGHS[i] + "C)");

}

final int clientWidth = table.getClientArea().width;

 

table.addListener(SWT.MeasureItemnew Listener() {

public void handleEvent(Event event) {

int itemIndex = table.indexOf((TableItem)event.item);

int rightX = (HIGHS[itemIndex] - SCALE_MIN) * clientWidth/SCALE_RANGE;

event.width = rightX;

}

});

table.addListener(SWT.EraseItemnew Listener() {

public void handleEvent(Event event) {

int itemIndex = table.indexOf((TableItem)event.item);

int leftX = (LOWS[itemIndex] - SCALE_MIN) * clientWidth/SCALE_RANGE;

int rightX = (HIGHS[itemIndex] - SCALE_MIN) * clientWidth/SCALE_RANGE;

GC gc = event.gc;

Rectangle clipping = gc.getClipping();

clipping.x = leftX;

clipping.width = rightX - leftX;

gc.setClipping(clipping);

 

Color oldForeground = gc.getForeground();

Color oldBackground = gc.getBackground();

gc.setForeground(blue);

gc.setBackground(white);

gc.fillGradientRectangle(event.x, event.y, event.width/2, event.heightfalse);

gc.setForeground(white);

gc.setBackground(red);

gc.fillGradientRectangle(

event.x + event.width/2, event.y, event.width/2, event.heightfalse);

gc.setForeground(oldForeground);

gc.setBackground(oldBackground);

event.detail &= ~SWT.BACKGROUND;

event.detail &= ~SWT.HOT;

}

});

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

// parliamentImage.dispose();

display.dispose();

}

}

 




 
这个程序画了渥太华的12个月的温度情况,画的非常的逼真啊。

 画法就是每一列的长度为【(HIGHS[itemIndex] - SCALE_MIN) * clientWidth/SCALE_RANGE;】,画的时候把gc中设置一个clipping,这样就只有这个回形针区域可以画上去了。然后两段都是渐进第一段蓝色到白色渐进,第二段是白色到红色渐进,蓝色表示冷,红色表示热了。还是比较形象的。

 

 3,SWT.PaintItem 

这个事件在默认的前景已经画好后,再调用。

这个事件的预定义的变量有:

· item: the item

· index: the column index of item being drawn

· xy: the table-relative co-ordinates of the top-left corner of the cell's content (ie.- its image or text)

· widthheight: the width and height of the cell's content; if these values were previously set by an SWT.MeasureItem listener then they are the same here

· gc: the GC configured with the default foreground, background, font and clipping for the cell

· detail: the logical OR of zero or more of the following bits: 

SWT.SELECTED: this bit will be set if the item is selected

SWT.FOCUSED: this bit will be set if the item is the table's focus item

SWT.HOT(@since 3.3) this bit will be set if the mouse hover background will be drawn for this cell (not all platforms draw this)

例子:

 

public class Snippet220 {

public static void main(String [] args) {

Display display = new Display();

Shell shell = new Shell(display);

shell.setBounds(10, 10, 350, 200);

Image xImage = new Image (display, 16, 16);

GC gc = new GC(xImage);

gc.setForeground(display.getSystemColor(SWT.COLOR_RED));

gc.drawLine(1, 1, 14, 14);

gc.drawLine(1, 14, 14, 1);

gc.drawOval(2, 2, 11, 11);

gc.dispose();

final int IMAGE_MARGIN = 2;

final Tree tree = new Tree(shell, SWT.CHECK);

tree.setBounds(10, 10, 300, 150);

TreeItem item = new TreeItem(tree, SWT.NONE);

item.setImage(xImage);

item.setText("root item");

for (int i = 0; i < 4; i++) {

TreeItem newItem = new TreeItem(item, SWT.NONE);

newItem.setText("descendent " + i);

if (i % 2 == 0) {

newItem.setData(xImage);

}

newItem.setImage(xImage);

item.setExpanded(true);

item = newItem;

}

 

tree.addListener(SWT.MeasureItemnew Listener() {

public void handleEvent(Event event) {

TreeItem item = (TreeItem)event.item;

Image trailingImage = (Image)item.getData();

if (trailingImage != null) {

event.width += trailingImage.getBounds().width + IMAGE_MARGIN;

}

}

});

tree.addListener(SWT.PaintItemnew Listener() {

public void handleEvent(Event event) {

TreeItem item = (TreeItem)event.item;

Image trailingImage = (Image)item.getData();

if (trailingImage != null) {

int x = event.x + event.width + IMAGE_MARGIN;

int itemHeight = tree.getItemHeight();

int imageHeight = trailingImage.getBounds().height;

int y = event.y + (itemHeight - imageHeight) / 2;

event.gc.drawImage(trailingImage, x, y);

}

}

});

 

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

xImage.dispose();

display.dispose();

}

}

 


 

 

 

在Item的后面,画图像。

可不可完全由我们来画,不好默认的呢?

下面例子:

 

public class Snippet231 {

public static void main(String [] args) {

final int COLUMN_COUNT = 4;

final int ITEM_COUNT = 8;

final int TEXT_MARGIN = 3;

Display display = new Display();

Shell shell = new Shell(display);

final Table table = new Table(shell, SWT.FULL_SELECTION);

table.setHeaderVisible(true);

table.setLinesVisible(true);

for (int i = 0; i < COLUMN_COUNT; i++) {

new TableColumn(table, SWT.NONE);

}

for (int i = 0; i < ITEM_COUNT; i++) {

TableItem item = new TableItem(table, SWT.NONE);

for (int j = 0; j < COLUMN_COUNT; j++) {

String string = "item " + i + " col " + j;

if ((i + j) % 3 == 1) {

string +="\nnew line1";

}

if ((i + j) % 3 == 2) {

string +="\nnew line1\nnew line2";

}

item.setText(j, string);

}

}

 

table.addListener(SWT.MeasureItemnew Listener() {

public void handleEvent(Event event) {

TableItem item = (TableItem)event.item;

String text = item.getText(event.index);

Point size = event.gc.textExtent(text);

event.width = size.x + 2 * TEXT_MARGIN;

event.height = Math.max(event.height, size.y + TEXT_MARGIN);

}

});

table.addListener(SWT.EraseItemnew Listener() {

public void handleEvent(Event event) {

event.detail &= ~SWT.FOREGROUND;

}

});

table.addListener(SWT.PaintItemnew Listener() {

public void handleEvent(Event event) {

TableItem item = (TableItem)event.item;

String text = item.getText(event.index);

/* center column 1 vertically */

int yOffset = 0;

if (event.index == 1) {

Point size = event.gc.textExtent(text);

yOffset = Math.max(0, (event.height - size.y) / 2);

}

event.gc.drawText(text, event.x + TEXT_MARGIN, event.y + yOffset, true);

}

});

 

for (int i = 0; i < COLUMN_COUNT; i++) {

table.getColumn(i).pack();

}

table.pack();

shell.pack();

shell.open();

while (!shell.isDisposed()) {

if (!display.readAndDispatch()) display.sleep();

}

display.dispose();

}

}

 

 



 
  

 表格中width取字符串宽加空白边框,height是字符串高加空白边框。这里的高和宽都是有GC计算的。

SWT.EraseItem事件取消的SWT.FOREGROUND事件,完全有我们自己去画了,画的时候用event.gc.drawText就行了。注意最后的column.pack()是必须的,前面没有设置column的宽度,调用pack才会计算column的宽度。

 

 文章看完了,比较的长,看几遍,有些问题还没有拓展。在网页上编辑,代码总是乱,没有办法只有在word编辑了再考上去了。

原文链接:http://www.eclipse.org/articles/article.php?file=Article-CustomDrawingTableAndTreeItems/index.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值