Java Swing: как вызвать событие, когда контекстное меню * закрывается * без выбора? - PullRequest
1 голос
/ 05 марта 2019

Я просматриваю Google уже два дня, немного потерян.

Я могу легко вызвать событие, когда срабатывает щелчок правой кнопкой мыши.Это не проблема.Моя проблема заключается в том, что мне также нужно вызвать аналогичное событие, если / когда меню, вызываемое правой кнопкой мыши, закрывается без какого-либо выбора.

Это сводится к бизнес-необходимости: в списке есть списоктаблица, у таблицы есть флажки в крайнем левом столбце, чтобы показать, какие строки были выбраны.Поскольку эти флажки предназначены для использования в качестве ключа пользовательского интерфейса для определения того, какие строки будут обрабатываться, любое действие обработки проверяет состояние флажков, а не то, какие строки были выбраны.

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

В этом случае запускщелчок правой кнопкой мыши на записи автоматически установит этот флажок (независимо от того, был ли он уже выбран).Однако, если пользователь решает не выполнять никаких действий с этой строкой, этот флажок необходимо вернуть в прежнее состояние (либо отмеченный, либо не отмеченный, вызванный нажатием правой кнопки мыши).

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

К сожалению, я ненашел в Интернете любых примеров, которые говорят о нацеливании на увольнение из меню, вызываемого правой кнопкой мыши, и о том, как подключить действие к этому событию.

Мой код такfar это что-то вроде этого:

private void setListenerForItemsTable() {
    tblItems.addMouseListener( new MouseAdapter() {
        public void mousePressed( MouseEvent evt ) {
            if ( view.showMaybePopup( evt ) ) {
                rightClickEvent(); // Fires needed code on right-click popup appearance.
            }
        }

        public void mouseReleased( MouseEvent evt ) {
            if ( view.showMaybePopup( evt ) ) {
                rightClickEvent();
            }
        }
    } );
}

, который творит чудеса при создании всплывающего окна, вызываемого правой кнопкой мыши.Он работает чудесно .

Как FYI, код также имеет прослушиватель для самого меню, вызываемого правой кнопкой мыши, что позволяет обрабатывать выбор любого элемента в этом меню, вызываемом правой кнопкой мыши.:

private void setListenerForRightClickMenu() {
    // Preview
    mnuPreviewItem.addActionListener( (e)
            -> {
        previewItem();
    } );

    // Resend Fax
    mnuResendItem.addActionListener( (e)
            -> {
        resendItem();
    } );

    /// etc...
}

Однако любая попытка использовать что-то вроде addFocusListener в меню правой кнопки мыши так же, как addMouseListener было прикреплено к таблице, вызывает исключение нулевого указателя;предположительно потому, что контекстное меню недоступно до тех пор, пока правый щелчок не будет запущен.

Предложения?

1 Ответ

0 голосов
/ 07 марта 2019

В двух словах, мое решение заключалось в добавлении второго слушателя к методу setListenerForItemsTable(), описанному выше.В частности, слушатель addPopupMenuListener():

tblItems.addPopupMenuListener( new PopupMenuListener() {
    @Override
    public void popupMenuWillBecomeVisible( PopupMenuEvent evt ) {
        // set checkbox
        if( rightClickRow >= 0 ) {
            mdlItems.setValueAt( true, rightClickRow, model.COL_CHECK );
        }
    }
    @Override
    public void popupMenuCanceled( PopupMenuEvent evt ) {
        // return checkbox to prior value
        if( rightClickRow >= 0 ) {
            mdlItems.setValueAt( rightClickValue, rightClickRow, model.COL_CHECK );
        }
    }
} );

Однако есть одна проблема: если таблица меньше, чем окно, в котором она находится, ваш щелчок правой кнопкой мыши может фактически не включать активно выбранную строку (если вы щелкнете правой кнопкой мыши в этой области, но не в какой-либо строке внутри самой таблицы).Таким образом, вам нужно нацелиться на любую строку, по которой вы щелкаете правой кнопкой мыши, , если она существует , а затем сохранить как номер этой строки, так и текущее состояние ее флажка (для обращения, если щелчок правой кнопкой мышизаброшен).

Таким образом, в корне нашего класса мы устанавливаем некоторые контейнеры по умолчанию для хранения этих значений:

private Boolean rightClickValue = false;
private int rightClickRow = -1;

, а затем нацеливаемся на addMouseListener(), чтобы увидеть, действительно ли мыщелкнув по строке и, если это так, запишите, какая это строка и какой у нее статус флажка:

tblItems.addMouseListener( new MouseAdapter() {
    @Override
    public void mouseClicked( MouseEvent evt ) {
        rightClickRow = tblItems.rowAtPoint( evt.getPoint() );
        rightClickValue = mdlItems.getValueAt(rightClickRow, model.COL_CHECK) == Boolean.TRUE;
    }
}

Итак, в итоге мы имеем следующее:

    /**
     * Listener to decide between showing right-click menu OR calling Preview Item after double clicking a row
     */
    private void setListenerForItemsTable() {

        tblItems.addMouseListener( new MouseAdapter() {
            @Override
            public void mouseClicked( MouseEvent evt ) {
                isPreview( evt );
            }

            @Override
            public void mousePressed( MouseEvent evt ) {
                processRightClick( evt );
            }

            @Override
            public void mouseReleased( MouseEvent evt ) {
                processRightClick( evt );
            }
        } );
        itmMenu.addPopupMenuListener( new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible( PopupMenuEvent evt ) {
                processCheckbox( true );
            }

            @Override
            public void popupMenuWillBecomeInvisible( PopupMenuEvent evt ) {
                // do nothing
            }

            @Override
            public void popupMenuCanceled( PopupMenuEvent evt ) {
                processCheckbox( rightClickValue );
            }
        } );
    }

    /**
     * Checks whether a preview of the line item is warranted, and provides it
     *
     * @param evt
     */
    private void isPreview( MouseEvent evt ) {
        if ( isRow( evt ) && isDblClick( evt ) ) {
            previewItem();
        }
    }

    /**
     * Checks if the item that was clicked on was a viable table row or not
     *
     * @param evt the MouseEvent
     *
     * @return Boolean
     */
    private Boolean isRow( MouseEvent evt ) {
        return getClickedRow( evt ) >= 0;
    }

    /**
     * Checks if the click action was a double click or not
     *
     * @param evt the MouseEvent
     *
     * @return Boolean
     */
    private Boolean isDblClick( MouseEvent evt ) {
        return evt.getClickCount() == 2;
    }

    /**
     * Gets the index of the table row that was clicked on
     *
     * @param evt the MouseEvent
     *
     * @return Integer
     */
    private Integer getClickedRow( MouseEvent evt ) {
        return tblItems.rowAtPoint( evt.getPoint() );
    }

    /**
     * Bringing everything together: storing the row index and value of the checkbox, and triggering the pop-up menu
     *
     * @param evt the MouseEvent
     */
    private void processRightClick( MouseEvent evt ) {
        int row = getClickedRow( evt );
        if ( row >= 0 ) {
            rightClickRow = row;
            rightClickValue = ( Boolean.TRUE ).equals( mdlItems.getValueAt( row, model.COL_CHECK ) );
        }
        view.showMaybePopup( evt );
    }

    /**
     * Setting or unsetting the checkbox in the active row
     *
     * @param value the desired value to apply to the checkbox
     */
    private void processCheckbox( Boolean value ) {
        if ( rightClickRow >= 0 ) {
            mdlItems.setValueAt( value, rightClickRow, model.COL_CHECK );
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...