如何查找SWT表列的索引?

时间:2013-06-25 05:16:19

标签: java swt

我有一个SWT表,它有零行和6列。

当我右键单击任何一个表头时,如何计算所单击的表列的索引?

5 个答案:

答案 0 :(得分:4)

我确实为CustomTable TableHeader写了一个Menu右键点击了一段时间。

此代码可帮助您检测右键单击表标题时的TableColumn。但是,当列顺序更改时,此代码会中断。但您可以通过比较重新排序的列顺序原始列顺序的索引来修复它。

addListener(SWT.MenuDetect, new Listener() {
        @Override
        public void handleEvent(Event e) {
            Point pt = getShell().getDisplay().map(null, CustomTable.this, new Point(e.x, e.y));
            Rectangle clientArea = CustomTable.this.getClientArea();
            boolean header = clientArea.y <= pt.y && pt.y < (clientArea.y + CustomTable.this.getHeaderHeight());
            //code to calculate column of Right click - START
            int width = 0;
            for(int i = 0; i< CustomTable.this.getColumns().length; i++){
                TableColumn tc = CustomTable.this.getColumns()[i];
                if(width < pt.x  &&  pt.x < width + tc.getWidth()){
                    System.out.println("Right Click on " + tc.getText());
                }
                width += tc.getWidth();
            }
            //code to calculate column of Right click - END
            if (header) {
                if(tableMenu != null){
                    tableMenu.setVisible(false);
                }
                CustomTable.super.setMenu(headerMenu);
                headerMenu.setLocation(e.x, e.y);
                headerMenu.setVisible(true);
                e.doit = false;
            } else {
                headerMenu.setVisible(false);
                CustomTable.super.setMenu(tableMenu);
                if(tableMenu != null){
                    tableMenu.setLocation(e.x, e.y);
                    tableMenu.setVisible(true);
                }
            }
        }
    });

答案 1 :(得分:3)

以下是一些可以满足您需求的代码:

private static Map<TableColumn, Integer> mapping = new HashMap<TableColumn, Integer>();

public static void main(String[] args)
{
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new FillLayout());

    Listener listener = new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            TableColumn column = (TableColumn) arg0.widget;

            System.out.println(mapping.get(column));
        }
    };

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

    for(int i = 0; i < 5; i++)
    {
        TableColumn column = new TableColumn(table, SWT.NONE);
        column.setText("Column " + i);
        column.addListener(SWT.Selection, listener);
        column.pack();

        mapping.put(column, i);
    }

    shell.pack();
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

它基本上生成Map,将TableColumn作为关键字,将位置存储为值。

或者,您可以迭代TableListener的所有列,并将它们与点击的列进行比较。第一种方法(Map)更快但使用更多内存,而第二种方法(迭代)更慢但使用更少的内存。

答案 2 :(得分:1)

与上面的示例类似,但没有使用地图来存储索引:

...
column.addSelectionListener(getSelectionAdapter1(tbl.getColumnCount()-1));    
...


private SelectionAdapter getSelectionAdapter1(final int index) {
    SelectionAdapter selectionAdapter = new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent e) {
            System.out.println(index);
        }
    };
    return selectionAdapter;
}

答案 3 :(得分:0)

表列定义中的

int index = 0;
TableColumn column1 = new TableColumn(table, SWT.NONE);
column1.setText("Column 1 header");
column1.setData(index);
index++;
TableColumn column2 = new TableColumn(table, SWT.NONE);
column2.setText("Column 2 header");
column2.setData(index);
index++;

处理程序中的

int index = (int) ((TableColumn) e.widget).getData();

答案 4 :(得分:0)

这是另一种看法。它只使用股票SWT表就可以明确地对右键单击做出反应,适用于标题和普通行,空表和完整表格。

此方法使用SWT.MenuDetect侦听器和&#34;伪TableItem&#34;的组合,创建和处理仅用于识别给定位置的列。我没有注意到任何不良的视觉副作用,如闪烁或闪光外观。这可能是由于虚假物品被放置在事件处理中,在UI的其余部分可以注意到它的存在之前。

SWT.MenuDetect侦听器对右键单击鼠标事件做出反应。不是很直观; name表明它主要用于规范上下文菜单外观,但它也可以作为一般的右键单击监听器。 与SWT.MouseDown不同,它也由表头发出。好! 不幸的是,与SWT.Selection不同,e.widget引用整个表,而不仅仅是列或单元格,因此在Baz响应中使用它对于我们的目的是无用的。必须使用物理坐标的低级方法检测色谱柱。

以下是代码:

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

/**
 * Table with right click detection that works for table headers and empty
 * tables. It was tested as working for columns reordering, moving or resizing.
 * 
 * @author Espinosa
 */
public class TableWithRightClickDetection {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("Table with right click detection");
        shell.setLayout(new FillLayout());
        shell.setSize(400, 300);

        final Table table = new Table(shell, SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        int columnCount = 4;
        for (int i = 0; i < columnCount; i++) {
            TableColumn column = new TableColumn(table, SWT.NONE);
            column.setText("Column " + i);
            column.setMoveable(true);
            column.setResizable(true);
            table.getColumn(i).pack();
        }

        table.addListener(SWT.MenuDetect, (e) -> {
            // SWT.MenuDetect reacts on right-click
            // It is emitted by table header, unlike SWT.MouseDown.
            // Also unlike SWT.Selection the e.widget references whole 
            // Table, not just column or cell, unfortunately, so this has 
            // to be detected using low level approach with physical coordinates.
            Point ptAbsolute = new Point(e.x, e.y);
            Point pt = table.toControl(ptAbsolute); // get position relative to the Tree widget
            int colIndex = columnAtPoint(table, pt);
            if (colIndex >= 0) {
                if (pt.y < table.getHeaderHeight())  {  
                    // for Tree/TreeViews negative Y means table header
                    System.out.println("Header right-clicked on column " + colIndex);
                } else {
                    System.out.println("Row right-clicked on column " + colIndex);
                }
            }
            // prevent showing context menu (if there is any declared)
            e.doit = false;
        });

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

    /**
     * @return column index for given coordinates relative to the given Table widget
     */
    private static int columnAtPoint(Table table, Point pt) {
        int colIndex = -1;
        // The only way how to get column bounds is to get TableItem
        // But empty table hasn't got any and headers does not count.
        // The only way is to temporarily create one and then immediately dispose.
        TableItem fakeRow = new TableItem(table, 0);
        for (int i = 0; i < table.getColumnCount(); i++) {
            Rectangle rec = fakeRow.getBounds(i);
            // It is safer to use X coordinate comparison directly rather then 
            // rec.contains(pt)
            // This way also works for Tree/TreeViews.
            if ((pt.x > rec.x)  && (pt.x < (rec.x + rec.width))) {
                colIndex = i;
            }
        }
        fakeRow.dispose();
        // Not the most efficient way. Rectangles obtained from "fake row" can be cached 
        // and recomputed on column resizes, moves and swaps.
        return colIndex;
    }
}

screenshot from the example app showing also console output from it