简体   繁体   English

如何查找SWT表列的索引?

[英]How to find index of SWT table column?

I have a SWT table which has zero rows and 6 columns. 我有一个SWT表,它有零行和6列。

When I right click on any one of the table header, how can I calculate the index of the table column that is clicked? 当我右键单击任何一个表头时,如何计算单击的表列的索引?

I did write a CustomTable for TableHeader Menu on Right click sometime back. 我确实在某个时候右键单击为TableHeader Menu编写了一个CustomTable

This code helps you in detecting the TableColumn on right click on table header. 此代码可帮助您在右键单击表头时检测TableColumn But, this code breaks when the column order is changed. 但是,当列顺序更改时,此代码会中断。 But you can fix it comparing the indices of reordered column order vs original column order. 但您可以通过比较重新排序的列顺序原始列顺序的索引来修复它。

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);
                }
            }
        }
    });

Here is some code that does what you want: 以下是一些可以满足您需求的代码:

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();
}

It basically generates a Map storing the TableColumn as key and the position as the value. 它基本上生成一个MapTableColumn存储为键,将位置存储为值。

Alternatively you could iterate over all the columns of the Table within the Listener and compare them to the clicked column. 另外,您可以遍历的所有列Table的内Listener ,并比较它们单击列。 The first approach (Map) is faster but uses more memory, whereas the second approach (iteration) is slower but uses less memmory. 第一种方法(Map)更快但使用更多内存,而第二种方法(迭代)更慢但使用更少的内存。

Similar to the above example, but without using a map to store indices: 与上面的示例类似,但没有使用地图来存储索引:

...
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;
}

in the tablecolumn definitions: 在表列定义中:

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++;

etc. 等等

in the handler: 在处理程序中:

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

here is another take. 这是另一种看法。 It definitively reacts on right click, works for headers and ordinary rows alike, empty tables and full tables alike, using just a stock SWT Table. 它只使用一个股票SWT表,明确地对右击做出反应,适用于标题和普通行,空表和全表。

This approach uses combination of SWT.MenuDetect listener and "fake TableItem", created and disposed just for identifying column at the given position. 此方法使用SWT.MenuDetect侦听器和“假TableItem”的组合,创建和处理仅用于标识给定位置的列。 I haven't noticed any undesirable visual side effect, like flickering or flash appearance. 我没有注意到任何不良的视觉副作用,如闪烁或闪光外观。 It is probably due to to the fake item being disposed inside event processing, before rest of the UI could take notice of its existence. 这可能是由于虚假物品被放置在事件处理中,在UI的其余部分可以注意到它的存在之前。

The SWT.MenuDetect listener reacts on right-click mouse event. SWT.MenuDetect侦听器对右键单击鼠标事件做出反应。 Not very intuitive; 不是很直观; name suggests it was intended mainly to regulate context menu appearance, but it does its job also as a general right click listener. name表明它主要用于规范上下文菜单外观,但它也可以作为一般的右键单击监听器。 It is emitted also by table header, unlike SWT.MouseDown. 与SWT.MouseDown不同,它也由表头发出。 Good! 好! Unfortunately, unlike SWT.Selection the e.widget references whole Table, not just column or cell, so is useless for our purposes as it is used in Baz response. 不幸的是,与SWT.Selection不同,e.widget引用整个表,而不仅仅是列或单元格,因此在Baz响应中使用它对于我们的目的是无用的。 The column has to he detected by using a low level approach with physical coordinates. 必须通过使用具有物理坐标的低级方法来检测该列。

Here is the code: 这是代码:

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;
    }
}

示例应用程序的屏幕截图,同时显示控制台输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM