The source of a custom table class for Java SWT applications : Table « SWT JFace Eclipse « Java

Java
1. 2D Graphics GUI
2. 3D
3. Advanced Graphics
4. Ant
5. Apache Common
6. Chart
7. Collections Data Structure
8. Database SQL JDBC
9. Design Pattern
10. Development Class
11. Email
12. Event
13. File Input Output
14. Game
15. Hibernate
16. J2EE
17. J2ME
18. JDK 6
19. JSP
20. JSTL
21. Language Basics
22. Network Protocol
23. PDF RTF
24. Regular Expressions
25. Security
26. Servlets
27. Spring
28. Swing Components
29. Swing JFC
30. SWT JFace Eclipse
31. Threads
32. Tiny Application
33. Velocity
34. Web Services SOA
35. XML
Microsoft Office Word 2007 Tutorial
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Java » SWT JFace Eclipse » TableScreenshots 
The source of a custom table class for Java SWT applications
The source of a custom table class for Java SWT applications


/*

de.kupzog.ktable.*  Version 1.4
_______________________________________________________________________

This is the source of a custom table class for Java SWT applications.

The original version of this table was written by Konstantin Scheglov. 
KTable is a complete new implementation but uses the structure and
some code fragments from the old version.

The features of this table implementation in short terms:

- a table model provides the data for the table (comparable
  to the Swing table model)
  
- cell rendering is done by extern classes and thus can easily
  be changed to any rendering one could imagine...
  
- Columns and rows can be resized by mouse. Note that all rows
  except the first row will have the same size.
  
- There can be horizontal and vertical headers (fixed cells)
  as many as needed.
  
- Different selection modes are available

- In place editing is possibel by using editor classes that
  can easily be adjusted to special needs.
  
  
For a detailed function description refer to the api documentation that 
is included in the sourcefiles.

For examples how to use KTable, see the "ExampleGUI" class. You can 
run this class and see different examples of KTables.

Text Table    Shows a Table with 1,000,000 rows and 100 columns.
        The use of cell editors is shown.
        You can resize rows and columns.
        Selection Listeners are used (see the console output).
        
Color Palette  Here you can see that a table does not have to
        look like a table...
        See how the cell renderer is implemented and 
        what the table model does.
        
Towns      This example shows how images can be included in
        table cells together with text. It also shows the use
        of the multi line cell editor.
        


The author welcomes any feedback:  fkmk@kupzog.de








Changes in Version 1.1 compared to previous version:

- empty table without header looks better now
- right-click on cell also changes the selection

Changes in Version 1.2
- License changed from GPL to LGPL
- Table does no longer throw NullPointerException if no model is set.
- minor other bug fixes

Changes in Version 1.3
- License changed from LGPL to Eclipse Public License (EPL) (what will be next?)
- Keyboard access for combo editors added (thanks to Larry Moore)
- minor other bug fixes

Changed in Version 1.4
- FLAT style allows more border flexibility: if specified,
  no border lines will be drawn.
- Click on fixed cells now also changes the row selection 
  (only in row selection mode with cells on the left border)
- bug fixes thanks to Chris Grant
*/

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Friederich Kupzog - initial API and implementation
 *      fkmk@kupzog.de
 *    www.kupzog.de/fkmk
 *******************************************************************************/

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;

/**
 * KTable example GUI
 
 
 */

public class ExampleGUI {
  public static void main(String[] args) {
    // create a shell...
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    shell.setText("KTable examples");

    // put a tab folder in it...
    TabFolder tabFolder = new TabFolder(shell, SWT.NONE);

    // Item 1: a Text Table
    TabItem item1 = new TabItem(tabFolder, SWT.NONE);
    item1.setText("Text Table");
    Composite comp1 = new Composite(tabFolder, SWT.NONE);
    item1.setControl(comp1);
    comp1.setLayout(new FillLayout());

    // put a table in tabItem1...
    KTable table = new KTable(comp1, SWT.V_SCROLL | SWT.H_SCROLL);
    // table.setRowSelectionMode(true);
    table.setMultiSelectionMode(true);
    table.setModel(new KTableModelExample());
    table.addCellSelectionListener(new KTableCellSelectionListener() {
      public void cellSelected(int col, int row, int statemask) {
        System.out.println("Cell [" + col + ";" + row + "] selected.");
      }

      public void fixedCellSelected(int col, int row, int statemask) {
        System.out
            .println("Header [" + col + ";" + row + "] selected.");
      }

    });

    table.addCellResizeListener(new KTableCellResizeListener() {
      public void columnResized(int col, int newWidth) {
        System.out.println("Column " + col + " resized to " + newWidth);
      }

      public void rowResized(int newHeight) {
        System.out.println("Rows resized to " + newHeight);
      }

    });

    // Item 2: a Color Palette
    TabItem item2 = new TabItem(tabFolder, SWT.NONE);
    item2.setText("Color Palette");
    Composite comp2 = new Composite(tabFolder, SWT.NONE);
    item2.setControl(comp2);
    comp2.setLayout(new FillLayout());

    // put a table in tabItem2...
    final KTable table2 = new KTable(comp2, SWT.NONE);
    table2.setModel(new PaletteExampleModel());
    table2.setRowSelectionMode(false);
    table2.setMultiSelectionMode(false);
    final Label label = new Label(comp2, SWT.NONE);
    label.setText("Click a cell...");
    table2.addCellSelectionListener(new KTableCellSelectionAdapter() {
      public void cellSelected(int col, int row, int statemask) {
        RGB rgb = (RGBtable2.getModel().getContentAt(col, row);
        label.setText("R: " + rgb.red + "\nG: " + rgb.green + "\nB: "
            + rgb.blue);
      }
    });

    // Item 3: Town table
    TabItem item3 = new TabItem(tabFolder, SWT.NONE);
    item3.setText("Towns");
    Composite comp3 = new Composite(tabFolder, SWT.NONE);
    item3.setControl(comp3);
    comp3.setLayout(new FillLayout());

    // put a table in tabItem3...
    final KTable table3 = new KTable(comp3, SWT.FLAT | SWT.H_SCROLL);
    table3.setBackground(Display.getCurrent().getSystemColor(
        SWT.COLOR_LIST_BACKGROUND));
    table3.setModel(new TownExampleModel());
    table3.setRowSelectionMode(true);
    table3.setMultiSelectionMode(false);

    // display the shell...
    shell.setSize(600600);
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch())
        display.sleep();
    }
    display.dispose();
  }
}

/*******************************************************************************
 * Copyright (C) 2004 by Friederich Kupzog Elektronik & Software All rights
 * reserved. This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 
 * Contributors: Friederich Kupzog - initial API and implementation
 * fkmk@kupzog.de www.kupzog.de/fkmk
 ******************************************************************************/

/**
 * Custom drawn tabel widget for SWT GUIs.
 
 
 @see de.kupzog.ktable.KTableModel
 @see de.kupzog.ktable.KTableCellRenderer
 @see de.kupzog.ktable.KTableCellEditor
 @see de.kupzog.ktable.KTableCellSelectionListener
 
 * The idea of KTable is to have a flexible grid of cells to display data in it.
 * The class focuses on displaying data and not on collecting the data to
 * display. The latter is done by the KTableModel which has to be implemented
 * for each specific case. The table asks the table model for the amount of
 * columns and rows, the sizes of columns and rows and for the content of the
 * cells which are currently drawn. Even if the table has a million rows, it
 * won't get slower because it only requests those cells it currently draws.
 * Only a bad table model can influence the drawing speed negatively.
 
 * When drawing a cell, the table calls a KTableCellRenderer to do this work.
 * The table model determines which cell renderer is used for which cell. A
 * default renderer is available (KTableCellRenderer.defaultRenderer), but the
 * creation of self-written renderers for specific purposes is assumed.
 
 * KTable allows to resize columns and rows. Each column can have an individual
 * size while the rows are all of the same height except the first row. Multiple
 * column and row headers are possible. These "fixed" cells will not be scrolled
 * out of sight. The column and row count always starts in the upper left corner
 * with 0, independent of the number of column headers or row headers.
 
 @author Friederich Kupzog
 
 */
class KTable extends Canvas {

  // Daten und Datendarstellung
  protected KTableModel m_Model;

  protected KTableCellEditor m_CellEditor;

  // aktuelle Ansicht
  protected int m_TopRow;

  protected int m_LeftColumn;

  // Selection
  protected boolean m_RowSelectionMode;

  protected boolean m_MultiSelectMode;

  protected HashMap m_Selection;

  protected int m_FocusRow;

  protected int m_FocusCol;

  protected int m_ClickColumnIndex;

  protected int m_ClickRowIndex;

  // wichtige MaBe
  protected int m_RowsVisible;

  protected int m_RowsFullyVisible;

  protected int m_ColumnsVisible;

  protected int m_ColumnsFullyVisible;

  // SpaltengroBe
  protected int m_ResizeColumnIndex;

  protected int m_ResizeColumnLeft;

  protected int m_ResizeRowIndex;

  protected int m_ResizeRowTop;

  protected int m_NewRowSize;

  protected boolean m_Capture;

  protected Image m_LineRestore;

  protected int m_LineX;

  protected int m_LineY;

  // sonstige
  protected GC m_GC;

  protected Display m_Display;

  protected ArrayList cellSelectionListeners;

  protected ArrayList cellResizeListeners;

  protected boolean flatStyleSpecified;

  // ////////////////////////////////////////////////////////////////////////////
  // KONSTRUKTOR
  // ////////////////////////////////////////////////////////////////////////////

  /**
   * Creates a new KTable.
   
   * possible styles: SWT.V_SCROLL - show vertical scrollbar and allow
   * vertical scrolling by arrow keys SWT.H_SCROLL - show horizontal scrollbar
   * and allow horizontal scrolling by arrow keys SWT.FLAT - no border
   * drawing.
   
   * After creation a table model should be added using setModel().
   */
  public KTable(Composite parent, int style) {
    // Oberklasse initialisieren
    super(parent, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | style);

    // inits
    m_GC = new GC(this);
    m_Display = Display.getCurrent();
    m_Selection = new HashMap();
    m_CellEditor = null;

    flatStyleSpecified = ((style | SWT.FLAT== style);

    m_RowSelectionMode = false;
    m_MultiSelectMode = false;
    m_TopRow = 0;
    m_LeftColumn = 0;
    m_FocusRow = 0;
    m_FocusCol = 0;
    m_RowsVisible = 0;
    m_RowsFullyVisible = 0;
    m_ColumnsVisible = 0;
    m_ColumnsFullyVisible = 0;
    m_ResizeColumnIndex = -1;
    m_ResizeRowIndex = -1;
    m_ResizeRowTop = -1;
    m_NewRowSize = -1;
    m_ResizeColumnLeft = -1;
    m_Capture = false;
    m_ClickColumnIndex = -1;
    m_ClickRowIndex = -1;

    m_LineRestore = null;
    m_LineX = 0;
    m_LineY = 0;

    cellSelectionListeners = new ArrayList(10);
    cellResizeListeners = new ArrayList(10);

    // Listener
    createListeners();

  }

  protected void createListeners() {

    addPaintListener(new PaintListener() {
      public void paintControl(PaintEvent event) {
        onPaint(event);
      }
    });

    addControlListener(new ControlAdapter() {
      public void controlResized(ControlEvent e) {
        redraw();
      }
    });

    addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {
        onMouseDown(e);
      }

      public void mouseUp(MouseEvent e) {
        onMouseUp(e);
      }

      public void mouseDoubleClick(MouseEvent e) {
        onMouseDoubleClick(e);
      }
    });

    addMouseMoveListener(new MouseMoveListener() {
      public void mouseMove(MouseEvent e) {
        onMouseMove(e);
      }
    });

    if (getVerticalBar() != null) {
      getVerticalBar().addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          m_TopRow = getVerticalBar().getSelection();
          redraw();
        }

      });
    }

    if (getHorizontalBar() != null) {
      getHorizontalBar().addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          m_LeftColumn = getHorizontalBar().getSelection();
          redraw();
        }
      });
    }
    addKeyListener(new KeyAdapter() {
      public void keyPressed(KeyEvent e) {
        onKeyDown(e);
      }
    });
  }

  // ////////////////////////////////////////////////////////////////////////////
  // Berechnungen
  // ////////////////////////////////////////////////////////////////////////////

  protected int getFixedWidth() {
    int width = 0;
    for (int i = 0; i < m_Model.getFixedColumnCount(); i++)
      width += m_Model.getColumnWidth(i);
    return width;
  }

  protected int getColumnLeft(int index) {
    if (index < m_Model.getFixedColumnCount()) {
      int x = 0;
      for (int i = 0; i < index; i++) {
        x += m_Model.getColumnWidth(i);
      }
      return x;
    }
    if (index < m_LeftColumn)
      return -1;
    int x = getFixedWidth();
    for (int i = m_LeftColumn; i < index; i++) {
      x += m_Model.getColumnWidth(i);
    }
    return x;
  }

  protected int getColumnRight(int index) {
    if (index < 0)
      return 0;
    return getColumnLeft(index+ m_Model.getColumnWidth(index);
  }

  protected int getLastColumnRight() {
    return getColumnRight(m_Model.getColumnCount() 1);
  }

  protected void doCalculations() {
    if (m_Model == null) {
      ScrollBar sb = getHorizontalBar();
      if (sb != null) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      }
      sb = getVerticalBar();
      if (sb != null) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      }
      return;
    }

    int m_HeaderHeight = m_Model.getFirstRowHeight();
    int m_RowHeight = m_Model.getRowHeight();

    Rectangle rect = getClientArea();
    if (m_LeftColumn < m_Model.getFixedColumnCount()) {
      m_LeftColumn = m_Model.getFixedColumnCount();
    }

    if (m_TopRow < m_Model.getFixedRowCount()) {
      m_TopRow = m_Model.getFixedRowCount();
    }

    int fixedWidth = getFixedWidth();
    int fixedHeight = m_HeaderHeight + (m_Model.getFixedRowCount() 1)
        * m_Model.getRowHeight();
    m_ColumnsVisible = 0;
    m_ColumnsFullyVisible = 0;

    if (m_Model.getColumnCount() > m_Model.getFixedColumnCount()) {
      int runningWidth = getColumnLeft(m_LeftColumn);
      for (int col = m_LeftColumn; col < m_Model.getColumnCount(); col++) {
        if (runningWidth < rect.width + rect.x)
          m_ColumnsVisible++;
        runningWidth += m_Model.getColumnWidth(col);
        if (runningWidth < rect.width + rect.x)
          m_ColumnsFullyVisible++;
        else
          break;
      }
    }

    ScrollBar sb = getHorizontalBar();
    if (sb != null) {
      if (m_Model.getColumnCount() <= m_Model.getFixedColumnCount()) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      else {
        sb.setMinimum(m_Model.getFixedColumnCount());
        sb.setMaximum(m_Model.getColumnCount());
        sb.setIncrement(1);
        sb.setPageIncrement(2);
        sb.setThumb(m_ColumnsFullyVisible);
        sb.setSelection(m_LeftColumn);
      }
    }

    m_RowsFullyVisible = Math.max(0(rect.height - fixedHeight)
        / m_RowHeight);
    m_RowsFullyVisible = Math.min(m_RowsFullyVisible, m_Model.getRowCount()
        - m_Model.getFixedRowCount());
    m_RowsFullyVisible = Math.max(0, m_RowsFullyVisible);

    m_RowsVisible = m_RowsFullyVisible + 1;

    if (m_TopRow + m_RowsFullyVisible > m_Model.getRowCount()) {
      m_TopRow = Math.max(m_Model.getFixedRowCount(), m_Model
          .getRowCount()
          - m_RowsFullyVisible);
    }

    if (m_TopRow + m_RowsFullyVisible >= m_Model.getRowCount()) {
      m_RowsVisible--;
    }

    sb = getVerticalBar();
    if (sb != null) {
      if (m_Model.getRowCount() <= m_Model.getFixedRowCount()) {
        sb.setMinimum(0);
        sb.setMaximum(1);
        sb.setPageIncrement(1);
        sb.setThumb(1);
        sb.setSelection(1);
      else {
        sb.setMinimum(m_Model.getFixedRowCount());
        sb.setMaximum(m_Model.getRowCount());
        sb.setPageIncrement(m_RowsVisible);
        sb.setIncrement(1);
        sb.setThumb(m_RowsFullyVisible);
        sb.setSelection(m_TopRow);
      }
    }
  }

  /**
   * Returns the area that is occupied by the given cell
   
   @param col
   @param row
   @return Rectangle
   */
  public Rectangle getCellRect(int col, int row) {
    int m_HeaderHeight = m_Model.getFirstRowHeight();
    if ((col < 0|| (col >= m_Model.getColumnCount()))
      return new Rectangle(-1, -100);

    int x = getColumnLeft(col1;
    int y;

    if (row == 0)
      y = 0;
    else if (row < m_Model.getFixedRowCount())
      y = m_HeaderHeight + ((row - 1* m_Model.getRowHeight());
    else
      y = m_HeaderHeight
          (m_Model.getFixedRowCount() + row - m_TopRow)
          * m_Model.getRowHeight();
    int width = m_Model.getColumnWidth(col1;
    int height = m_Model.getRowHeight() 1;
    if (row == 0)
      height = m_Model.getFirstRowHeight() 1;

    return new Rectangle(x, y, width, height);
  }

  protected boolean canDrawCell(int col, int row, Rectangle clipRect) {
    Rectangle r = getCellRect(col, row);
    return canDrawCell(r, clipRect);
  }

  protected boolean canDrawCell(Rectangle r, Rectangle clipRect) {
    if (r.y + r.height < clipRect.y)
      return false;
    if (r.y > clipRect.y + clipRect.height)
      return false;
    if (r.x + r.width < clipRect.x)
      return false;
    if (r.x > clipRect.x + clipRect.width)
      return false;
    return true;
  }

  // ////////////////////////////////////////////////////////////////////////////
  // ZEICHNEN
  // ////////////////////////////////////////////////////////////////////////////

  // Paint-Ereignis

  protected void onPaint(PaintEvent event) {
    Rectangle rect = getClientArea();
    GC gc = event.gc;

    doCalculations();

    if (m_Model != null) {

      drawBottomSpace(gc);
      drawCells(gc, gc.getClipping()0, m_Model.getFixedColumnCount(),
          0, m_Model.getFixedRowCount());
      drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model
          .getColumnCount()0, m_Model.getFixedRowCount());
      drawCells(gc, gc.getClipping()0, m_Model.getFixedColumnCount(),
          m_TopRow, m_TopRow + m_RowsVisible);
      drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model
          .getColumnCount(), m_TopRow, m_TopRow + m_RowsVisible);
    else {
      gc.fillRectangle(rect);
    }
  }

  // Bottom-Space

  protected void drawBottomSpace(GC gc) {
    Rectangle r = getClientArea();
    if (m_Model.getRowCount() 0) {
      r.y = m_Model.getFirstRowHeight()
          (m_Model.getFixedRowCount() + m_RowsVisible)
          * m_Model.getRowHeight() 1;
    }

    gc.setBackground(getBackground());
    gc.fillRectangle(r);
    gc.fillRectangle(getLastColumnRight() 2