Eclipse Plug-in - How to use GC to build graphics on TableViewer column

這邊要提到的是如何在TableViewer column 以圖形的方式顯示,如以長條圖加上文字來表達!

在此將要利用到的是Graphics Context(GC class)來繪製!

首先要先從如何建置TableViewer來開始,它是在View下面作呈現的

主程式 - TableDisplayView.java
  1. public class TableDisplayView extends ViewPart{
  2. private TableViewer viewer;
  3. private String title[] = {"Name", "Price", "Percent Graphics Bar"};
  4. private int width[] = {150, 150, 600};
  5. @Override
  6. public void createPartControl(Composite parent) {
  7. // TODO Auto-generated method stub
  8. viewer = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION);
  9. viewer.setContentProvider(new ArrayContentProvider());
  10. Table table = viewer.getTable();
  11. createColumns();
  12. table.setHeaderVisible(true);
  13. table.setLinesVisible(true);
  14. ShoppingGenerator generator = new ShoppingGenerator();
  15. viewer.setInput(generator.getProvider());
  16. }
  17. }

因為是在Eclipse's View下面呈現,因此需繼承相關的類別ViewPart

plugin.xml
<extension point="org.eclipse.ui.views">
    <view
        category="org.eclipse.ui"
        class="com.bin.practice.ui.TableDisplayView"
        id="com.bin.practice.ui.TableDisplayView"
        name="TableDisplayView"
        restorable="true">
    </view>
</extension>


再者,定義要建置的主畫面TableViewer容器

一、資料格式

若setContentProvider內利用ArrayContentProvider,對應到setInput傳入的Object將會是

Array type elements,在此為自訂的bean - Shopping.java及產生器ShoppingGenerator.java

  1. public class Shopping {
  2. private String name;
  3. private int price;
  4. private float percent;
  5. public Shopping(String name, int price) {
  6. super();
  7. this.name = name;
  8. this.price = price;
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public int getPrice() {
  14. return price;
  15. }
  16. public float getPercent() {
  17. return percent;
  18. }
  19. public void setPercent(float percent) {
  20. this.percent = percent;
  21. }
  22. }
  1. public class ShoppingGenerator {
  2. Shopping shoppings[];
  3. public Shopping[] getProvider(){
  4. String names[] = {"shoes", "watch", "clothes", "book", "bike"};
  5. int prices[] = {1300, 2500, 780, 350, 3600};
  6. shoppings = new Shopping[names.length];
  7. for(int i = 0 ; i < shoppings.length ; i++){
  8. shoppings[i] = new Shopping(names[i], prices[i]);
  9. }
  10. calculatePercent();
  11. return shoppings;
  12. }
  13. private void calculatePercent(){
  14. int total = Stream.of(shoppings).mapToInt(s -> s.getPrice()).sum();
  15. Stream.of(shoppings).forEach(s -> {
  16. s.setPercent(((float)s.getPrice()/(float)total)*100);
  17. });
  18. }
  19. }

二、定義column格式
  1. private void createColumns(){
  2. for(int i = 0 ; i < title.length ; i++){
  3. TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
  4. TableColumn column = viewerColumn.getColumn();
  5. column.setText(title[i]);
  6. column.setWidth(width[i]);
  7. if(i == title.length - 1)
  8. viewerColumn.setLabelProvider(new DrawGraphicsProvider());
  9. else
  10. viewerColumn.setLabelProvider(new TableLabelProvider(title[i]));
  11. }
  12. }

在這邊要注意的是,每個column都有它需要定義的setLabelProvider,要表達的就是這個

column內的資料要以什麼資料來呈現?! 在這邊就要定義清楚!

若是一般的資料請見 - TableLabelProvider.java

若是該欄要呈現圖形資料請見 - DrawGraphicsProvider.java

PS. 以上兩個類別皆為自訂類別,但繼承相關需被衍生的類別

文字或數字資料 - TableLabelProvider.java
  1. public class TableLabelProvider extends ColumnLabelProvider{
  2. private String title;
  3. public TableLabelProvider(String title){
  4. this.title = title;
  5. }
  6. @Override
  7. public String getText(Object element) {
  8. if(element instanceof Shopping){
  9. try {
  10. Method method = Shopping.class.getDeclaredMethod(getGetterMethod(title));
  11. Object value = method.invoke(element);
  12. return value+"";
  13. } catch (Exception e) {
  14. // TODO Auto-generated catch block
  15. e.printStackTrace();
  16. }
  17. }
  18. return "";
  19. }
  20. public String getGetterMethod(String name){
  21. return "get"+name.substring(0);
  22. }
  23. }

在此繼承ColumnLabelProvider,在覆寫getText時傳進來的element即為setInput傳進去的某一

筆Array資料,這個資料在此為Shopping.java;再利用Java Reflect以傳進來的title name來呼叫

Shopping相關method,並以此得到的資料作為getText()回傳!

圖形呈現 - DrawGraphicsProvider.java

這邊要展示的為本篇的重頭戲,如何畫出圖形
  1. public class DrawGraphicsProvider extends OwnerDrawLabelProvider{
  2. @Override
  3. protected void measure(Event event, Object element) {
  4. // TODO Auto-generated method stub
  5. }
  6. @Override
  7. protected void paint(Event event, Object element) {
  8. // TODO Auto-generated method stub
  9. if(!(element instanceof Shopping)){
  10. return;
  11. }
  12. Shopping node = (Shopping) element;
  13. Table tree = (Table) event.widget;
  14. //Display display = tree.getDisplay();
  15. //Color bg = new Color(display.getCurrent(), 218, 224, 222); //background color
  16. GC gc = event.gc;
  17. int widthcol = tree.getColumn(event.index).getWidth();
  18. int totalProgBarLength = (int)(widthcol * 0.8); //This makes it grow/shrink dynamically.
  19. if (totalProgBarLength > 0) {
  20. //---- Shared elements
  21. int oriX = event.x;
  22. int oriY = event.y;
  23. int barHeight = (int) (event.height * 0.8);
  24. float percent = node.getPercent();
  25. gc.setBackground(getColor(event, SWT.COLOR_DARK_GREEN));
  26. gc.fillRectangle(oriX, oriY, totalProgBarLength, barHeight);
  27. //---- Draw dark red bar for price percent
  28. int progBarRedWidth = getWithByScale(totalProgBarLength, percent);
  29. gc.setBackground(getColor(event, SWT.COLOR_DARK_RED));
  30. gc.fillRectangle(oriX, oriY, progBarRedWidth, barHeight);
  31. //---- Draw percent text
  32. gc.setForeground(getColor(event, SWT.COLOR_BLACK));
  33. int offsetX = oriX + totalProgBarLength + (int)(widthcol * 0.05);
  34. int offsetY = oriY;
  35. gc.drawText(String.valueOf(percent), offsetX, offsetY, true);
  36. }
  37. //bg.dispose();
  38. }
  39. private Color getColor(Event event, int color){
  40. Display display = event.widget.getDisplay();
  41. return display.getSystemColor(color);
  42. }
  43. /**
  44. * add 0.5 is for rounding because convert to int
  45. * @param originalWith
  46. * @param percent
  47. * @return
  48. */
  49. private int getWithByScale(int originalWith, float percent){
  50. return (int) ((originalWith * (percent * 0.01)) + 0.5);
  51. }
  52. }

繼承OwnerDrawLabelProvider.java後,重新定義paint method

由它傳進來的event可取得Display、GC、Widget等resource,另element即為Shopping

先針對column取得其width

1. 畫取底圖 - 深綠色長條圖

自訂底圖顏色
gc.setBackground(getColor(event, SWT.COLOR_DARK_GREEN));
畫取填滿的長方形,前兩個參數為左上角的起點,再延伸其長度、高度
gc.fillRectangle(oriX, oriY, totalProgBarLength, barHeight);

2. 畫取比例圖 - 深紅色長條圖

底圖畫好後,接下來要畫的就是算出來的percent在此底圖上共佔了多少比例

3. 畫取純文字

文字的部分無設定background表示無底圖顏色
gc.setForeground(getColor(event, SWT.COLOR_BLACK));
第四個參數為true表示底圖是透明的
gc.drawText(String.valueOf(percent), offsetX, offsetY, true);

4. 自訂Color

若要自訂顏色,請自行new Color,但別忘了需自己dispose掉!
Display display = tree.getDisplay();
Color bg = new Color(display.getCurrent(), 218, 224, 222); //background color

三、DEMO

簡單的利用GC來繪製TableViewer上的column圖形在此也算是大功告成!

留言