Java Swing:当右键单击菜单在未进行选择的情况下被*取消*时,如何触发事件?
我已经浏览谷歌两天了,有点不知所措 当右键单击被触发时,我可以轻松触发事件。这不是问题。我的问题是,如果/当右键菜单在没有进行任何选择的情况下被取消时,我还需要触发类似的事件 这归结为一个业务需求:表中有一个项目列表,该表最左边的列中有复选框,以显示已选择的行。由于这些复选框是确定要处理哪些行的UI键,因此任何处理操作都会查看复选框的状态,而不是已选择哪些行 用户可以直接选择复选框对一行或多行执行操作(通过窗口页脚中的按钮或通过右键单击菜单)。但是,还需要通过右键单击事件本身进行单个活动选择,而无需显式选中复选框 在这种情况下,触发右键单击条目将自动选中该复选框(无论是否已选中)。但是,如果用户决定不对该行执行任何操作,则需要将该复选框恢复到其先前的状态(选中或未选中,通过右键单击触发) 通过只使用原始状态,我不必关心原始状态,只需要在放弃右键单击时重新应用它。这允许成功恢复选中和未选中的原始状态。从本质上说,这允许取消意外的右键单击,而无需每次都在表格行中勾选复选框,这将是不希望出现的行为 不幸的是,我在互联网上还没有找到任何关于取消右键菜单的例子,以及如何将一项行动与该事件挂钩 到目前为止,我的代码是这样的:Java Swing:当右键单击菜单在未进行选择的情况下被*取消*时,如何触发事件?,java,swing,Java,Swing,我已经浏览谷歌两天了,有点不知所措 当右键单击被触发时,我可以轻松触发事件。这不是问题。我的问题是,如果/当右键菜单在没有进行任何选择的情况下被取消时,我还需要触发类似的事件 这归结为一个业务需求:表中有一个项目列表,该表最左边的列中有复选框,以显示已选择的行。由于这些复选框是确定要处理哪些行的UI键,因此任何处理操作都会查看复选框的状态,而不是已选择哪些行 用户可以直接选择复选框对一行或多行执行操作(通过窗口页脚中的按钮或通过右键单击菜单)。但是,还需要通过右键单击事件本身进行单个活动选择,而
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();
}
}
} );
}
这在创建右键单击弹出窗口方面非常有效。它工作得很好
仅供参考,该代码还为右键单击菜单本身提供了一个侦听器,允许处理该右键单击菜单中任何项目的选择:
private void setListenerForRightClickMenu() {
// Preview
mnuPreviewItem.addActionListener( (e)
-> {
previewItem();
} );
// Resend Fax
mnuResendItem.addActionListener( (e)
-> {
resendItem();
} );
/// etc...
}
但是,任何尝试在右键单击菜单上使用类似于addFocusListener
的内容的行为都会导致空指针异常,其方式与将addMouseListener
附加到表的方式相同;大概是因为在实际触发右键单击之前,右键单击菜单不可用
建议?简而言之,我的解决方案是向上面的
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 );
}
}
简而言之,我的解决方案是向上面的
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 );
}
}
可能的副本我不认为它是副本。我的问题甚至比这个问题更为根本:首先,我试图将某种侦听器附加到右键单击菜单,但发现自己无法(和/或不知道如何)这样做。可能的重复我不认为它是重复的。我的问题甚至比这个问题更为根本:首先,我试图在右键菜单上附加某种侦听器,但发现自己无法(和/或不知道如何)这样做。