Отображение контекстного меню NatTable

Я использую NatTable. Как показать пункт контекстного меню при определенном условии в зависимости от содержимого ячейки? А как выделить ячейку, над которой вызывалось контекстное меню? Я связываю меню со следующим кодом

uiBindingRegistry.registerMouseDownBinding(
            new MouseEventMatcher(SWT.NONE, null, MouseEventMatcher.RIGHT_BUTTON), new PopupMenuAction(menu));

UPD: Я создаю такое меню, но пункт «Тест» виден, несмотря на то, что isActive всегда возвращает false. Что с этим не так?

menu = new PopupMenuBuilder(natTable).withMenuItemProvider(ITEM_ID, new IMenuItemProvider() {
        @Override
        public void addMenuItem(final NatTable natTable, final Menu popupMenu) {
            final MenuItem menuItem = new MenuItem(popupMenu, SWT.PUSH);
            menuItem.setText("Test");
            menuItem.setEnabled(true);
            menuItem.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(final SelectionEvent event) {
                    System.out.println("test");
                }
            });
        }
    }).withVisibleState(ITEM_ID, new IMenuItemState() {
        @Override
        public boolean isActive(final NatEventData natEventData) {
            return false;
        }
    }).build();

person Joel    schedule 12.01.2016    source источник
comment
Если константа ITEM_ID не равна нулю, в этом коде нет ничего плохого. Вопрос в том, где вы создаете меню? Я создаю его непосредственно в AbstractUiBindingConfiguration, и он работает по назначению.   -  person Dirk Fauth    schedule 13.01.2016
comment
@Dirk Fauth Я нашел причину. В CellPopupMenuAction run() у меня есть menu.setData(event.data), но должно быть menu.setData(MenuItemProviders.NAT_EVENT_DATA_KEY, event.data). Тогда все работает как задумано.   -  person Joel    schedule 14.01.2016
comment
спасибо за подсказку... совсем забыл про эту деталь. Я обновил пример кода в своем ответе, чтобы правильно отразить это.   -  person Dirk Fauth    schedule 14.01.2016
comment
Я снова нашел причину bugs.eclipse.org/bugs/show_bug.cgi? id=451490 Какую версию Eclipse/JFace вы используете?   -  person Dirk Fauth    schedule 14.01.2016
comment
@Дирк Фаут 4.3.0/3.9.1   -  person Joel    schedule 14.01.2016


Ответы (3)


Приведенный ответ правильный. Хотя его можно улучшить. Вам не нужен SelectionLayer.

class CellPopupMenuAction implements IMouseAction {

    private final Menu menu;

    public CellPopupMenuAction(Menu menu) {
        this.menu = menu;
    }

    @Override
    public void run(NatTable natTable, MouseEvent event) {
        int columnPosition = natTable.getColumnPositionByX(event.x);
        int rowPosition = natTable.getRowPositionByY(event.y);

        ILayerCell cell = natTable.getCellByPosition(columnPosition, rowPosition);

        if (!cell.getDisplayMode().equals(DisplayMode.SELECT)) {
            natTable.doCommand(
                    new SelectCellCommand(
                            natTable,
                            columnPosition,
                            rowPosition,
                            false,
                            false));
        }

        menu.setData(MenuItemProviders.NAT_EVENT_DATA_KEY, event.data);
        menu.setVisible(true);
    }
}

Таким образом, вы полностью избавитесь от необходимости ссылаться на SelectionLayer и даже улучшите функциональность, потому что SelectCellCommand никогда не запускается, если вы щелкнете правой кнопкой мыши по выбранной ячейке.

person Dirk Fauth    schedule 13.01.2016
comment
Спасибо. И как я могу отображать разные элементы в меню в зависимости от состояния (содержимого ячейки)? - person Joel; 13.01.2016
comment
Если вы используете NatTable PopupMenuBuilder, вы можете создать и добавить IMenuItemState, чтобы указать условия для включенных или видимых состояний. - person Dirk Fauth; 13.01.2016
comment
Я использую Менеджер меню. Есть ли способ использовать IMenuItemState в этом случае? - person Joel; 13.01.2016
comment
На самом деле вам нужен MenuManager для создания PopupMenuBuilder, чтобы использовать IMenuItemState. Для контекстных меню NatTable с доступом к содержимому NatTable всегда рекомендуется именно этот способ. - person Dirk Fauth; 13.01.2016
comment
Не могли бы вы взглянуть на обновленный вопрос? Пункт меню всегда виден, хотя я использую IMenuItemState, который всегда имеет значение false - person Joel; 13.01.2016
comment
Еще один вопрос. Есть ли способ получить это меню из тестовой среды? Я могу получить ссылку на NatTable (и даже показать это меню), но понятия не имею, как получить ссылку на нее. - person Joel; 19.01.2016
comment
Я не думаю, что это возможно без модификаций прямо сейчас. Меню не устанавливается для экземпляра NatTable, но сохраняется в действии. Это сделано специально, поскольку это позволяет вам иметь несколько разных меню в одном NatTable на основе разных условий (например, разных областей сетки). Вы можете попробовать обходной путь, используя прослушиватель меню в своем меню, который добавляет меню через NatTable#setMenu() при отображении меню и удаляет его при скрытии меню. Таким образом, он будет доступен, когда он будет виден. Но я еще не проверял это, это просто идея. - person Dirk Fauth; 20.01.2016
comment
Спасибо за подсказку. Мой первый подход состоял в том, чтобы вызвать NatTable#setMenu() после создания меню. Но в тесте у меня меню без пунктов. Когда я вызываю NatTable#setMenu() в MenuListener, как вы предложили, я получаю то, что хочу - person Joel; 20.01.2016

Вам нужно IMouseAction для выбора ячейки. Пример кода из здесь и добавлен дополнительный код для выбора вызов добавлен поверх него ниже:

nattable.addConfiguration( new AbstractUiBindingConfiguration()

    uiBindingRegistry.registerMouseDownBinding( new MouseEventMatcher( SWT.NONE, GridRegion.BODY,
                            MouseEventMatcher.RIGHT_BUTTON ), new CellPopupMenuAction(menu, selectionLayer) );


});

class CellPopupMenuAction implements IMouseAction {

                private final Menu menu;
                private final SelectionLayer selectionLayer;

                public CellPopupMenuAction(Menu menu, SelectionLayer selectionLayer) {
                    this.menu = menu;
                    this.selectionLayer = selectionLayer;
                }

                @Override
                public void run(NatTable natTable, MouseEvent event) 
                {
                    if( selectionLayer.getSelectedRowCount() <= 1 )
                            {
                                int colPosition = LayerUtil.convertColumnPosition( natTable,
                                        natTable.getColumnPositionByX( event.x ), selectionLayer );
                                int rowPosition = LayerUtil.convertRowPosition( natTable,
                                        natTable.getRowPositionByY( event.y ), selectionLayer );

                                natTable.doCommand( new SelectCellCommand( selectionLayer, colPosition, rowPosition, false,
                                        false ) );
                            }
                    menu.setData(event.data);
                    menu.setVisible(true);
                }
            }

Я предполагаю, что у вас есть selectionLayer как частная переменная в вашем коде.

person SomeDude    schedule 13.01.2016
comment
Спасибо за подборку, все работает именно так, как я хочу. Я просмотрел предоставленную ссылку и, насколько я понимаю, она показывает меню при условии. Но мне нужно показывать разные элементы в меню в зависимости от состояния. И я до сих пор понятия не имею, как этого добиться - person Joel; 13.01.2016

Я использовал ответ SomeDude выше, и это сработало, но пункт меню отображался перед выбором, который выглядел странно. Я переместил отображение меню в вызов asyncExec потока пользовательского интерфейса, и сначала происходит выбор, а затем поверх него появляется меню -

@Override
public void run(NatTable natTable, MouseEvent event) {

    if (selectionLayer.getSelectedRowCount() <= 1) {

        int colPosition = LayerUtil.convertColumnPosition(natTable, natTable.getColumnPositionByX(event.x),
                selectionLayer);

        int rowPosition = LayerUtil.convertRowPosition(natTable, natTable.getRowPositionByY(event.y),
                selectionLayer);

        natTable.doCommand(new SelectCellCommand(selectionLayer, colPosition, rowPosition, false, false));

    }

    Display.getDefault().asyncExec(new Runnable() {
        public void run() {
            menu.setData(event.data);
            menu.setVisible(true);
        }
    });

}
person Jason Berry    schedule 29.04.2018