【问题标题】:How to find index of SWT table column?如何查找 SWT 表列的索引?
【发布时间】:2013-06-25 05:16:19
【问题描述】:

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

当我右击任一表头时,如何计算被点击的表列的索引?

【问题讨论】:

    标签: java swt


    【解决方案1】:

    我确实为TableHeader Menu 写了一个CustomTable 右键单击​​返回。

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

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

    【讨论】:

    • 如果表格控件有一个不在开头的水平滚动条,这段代码会起作用吗?
    • @MikeNakis 它应该,因为 headerHeight 和 clientArea 计算 w.r.t 滚动条(如果存在)。试一试。
    • 我不认为 clientArea 是 w.r.t 滚动条计算的,无论如何,您没有在计算中使用 clientArea.x 来查找列,所以在我看来,即使clientArea 受滚动影响。既然您已经有了代码,大概是您编写的某个应用程序的一部分,您为什么不尝试一下并告诉我们?
    【解决方案2】:

    这里有一些代码可以满足你的需求:

    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 存储为键,将位置存储为值。

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

    【讨论】:

    • 非常感谢漂亮的 sn-p:) 这在列选择时工作正常,但在列右键单击时却不行。我尝试将 SWT.Selection 修改为 SWT.MouseDown ,但没有成功。有什么意见吗?
    • @yash 有一个相当老的错误报告here 表明TableColumn 标头不支持右键单击。
    • @yash 但是,如果您使用的是右键菜单,您可以查看this 代码示例并使用SWT.MenuDetect
    • 其实我正在使用 IMenuListener->menuAboutToShow() 在右键单击表格标题时添加其他操作。
    • @yash 你不能以某种方式从Listener 获取用户点击的TableColumn 吗?
    【解决方案3】:

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

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

    【讨论】:

    • 请注意,这仅适用于未移动列的情​​况。移动列后,您必须使用 table.getColumnOrder() 来确定列的索引。
    【解决方案4】:

    在表格列定义中:

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

    【讨论】:

      【解决方案5】:

      这是另一种说法。它会在右键单击时做出明确反应,适用于标题和普通行,空表和完整表,只使用一个股票 SWT 表。

      此方法使用 SWT.MenuDetect 侦听器和“假 TableItem”的组合,创建和处理只是为了识别给定位置的列。我没有注意到任何不良的视觉副作用,例如闪烁或闪光外观。这可能是由于假项目在事件处理中被处置,在其余 UI 可以注意到它的存在之前。

      SWT.MenuDetect 侦听器对鼠标右键单击事件作出反应。不是很直观;顾名思义,它主要是为了规范上下文菜单的外观,但它也可以作为一个通用的右键单击侦听器。 与 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-11
        • 1970-01-01
        • 2019-04-08
        • 1970-01-01
        • 2021-12-24
        • 2013-05-08
        相关资源
        最近更新 更多