Prevent action in TListView's context menu when in edit mode

Viewed 81

I'm using C++Builder XE6 to write a VCL application that contains a TListView with an associated TPopupMenu context menu.

The TListView has ViewStyle=vsReport and ReadOnly=false. The associated context menu contains a 'Delete' menu item with ShortCut=Del.

The 'Delete' menu item has the following OnClick event handler:

void __fastcall TForm1::Delete1Click (TObject *Sender)
{
    ListView1->DeleteSelected();
}

The 'Delete' menu item is enabled/disabled in the OnPopup event handler of the context menu:

void __fastcall TForm1::PopupMenu1Popup (TObject *Sender)
{
    Delete1->Enabled = (ListView1->SelCount > 0);
}

When I select an item in the list view and press the Del key on the keyboard, the Delete1Click() event handler is invoked and the item is deleted, as expected.

However, if the list view item is in edit mode and I press the Del key, the Delete1Click() event handler is also invoked, deleting the item. The keypress is not sent to the edit box in the list view.

I tried to fix this by modifying the OnPopup event handler of the context menu as follows:

void __fastcall TForm1::PopupMenu1Popup (TObject *Sender)
{
    Delete1->Enabled = (ListView1->SelCount > 0 && !ListView1->IsEditing());
}

This prevents the deletion of the list view item, but the keypress is still not sent to the edit box in the list view.

When the list view item is in edit mode, the Del keypress should be handled by the edit box of the list view instead of invoking the Delete1Click() event handler.

How do I achieve this?

I don't want to change the shortcut for the 'Delete' menu item, to something like Ctrl+Del.

3 Answers

To overcome your problem, you need to clear the menu item's shortcut when editing a list item, by adding OnEditing and OnEdited event handlers to the TListView.

void __fastcall TForm3::ListView1Editing(TObject *Sender, TListItem *Item, bool &AllowEdit)
{
if(Delete1->ShortCut != NULL) //added
    {

    shortCut = Delete1->ShortCut; //added
    Delete1->ShortCut = NULL;
    }
}

Pressing the keyboard Del key will act as it should while you are editing, when finished editing you can reinstate the shortcut like this:

void __fastcall TForm3::ListView1Edited(TObject *Sender, TListItem *Item, UnicodeString &S)
{
//  omit ->  Delete1->ShortCut = TextToShortCut("Del") ; 
//  replace with

Delete1->ShortCut = shortCut;
}

Adding these two event handlers work fine in XE7, so you should have no problem with XE6.

You could also, while you are at it, store the menu item's shortcut in a TShortCut, then restore from that for each menu item with a shortcut that you are having issues with.

Edit: as a workaround for the ESC problem, adding an OnContextPopup could be used to reinstate the shortcut if the short cut was removed from Delete1

Updated answer to reflect changes

Add a TShortCut shortCut variable to your form.

void __fastcall TForm3::ListView1ContextPopup(TObject *Sender, TPoint &MousePos, bool &Handled)

    {
    if(shortCut != 0)
        {
        Delete1->ShortCut = shortCut;
        shortCut = NULL;
        }
    }
 

The following code handles the Del keypress in both circumstances, without removing the menu item shortcut. When the list view is not in edit mode, DeleteSelected() is called to delete the selected items in the list view. When the list view is in edit mode (i.e. an item is being edited), the code simulates a Del keypress in the edit box of the list view, using SendMessage().

void __fastcall TForm1::Delete1Click (TObject *Sender)
{
    if (ListView1->IsEditing()) // Check if list view item is being edited.
    {
        HWND Edit = ListView_GetEditControl(ListView1->Handle); // Get handle to edit window.

        if (Edit)
        {
            UINT Scan = MapVirtualKey(VK_DELETE, MAPVK_VK_TO_VSC);  // Get scan code of Del key.

            SendMessage(Edit, WM_KEYDOWN, VK_DELETE, 0x00000001 | Scan << 16);  // Simulate Del keypress in edit window.
            SendMessage(Edit, WM_KEYUP,   VK_DELETE, 0xC0000001 | Scan << 16);
        }
    }
    else
        ListView1->DeleteSelected();    // Delete selected items in list view.
}

void __fastcall TForm1::PopupMenu1Popup (TObject *Sender)
{
    Delete1->Enabled = (ListView1->SelCount > 0);
}

See the documentation for WM_KEYDOWN and WM_KEYUP for a description of the bits used in the lparam parameter.

Just a thought, you should be able to set a flag 'is_editing = true' when you select the ListView1 Item and use the flag to skip ListView1->DeleteSelected(); with something like

void __fastcall TForm1::Delete1Click (TObject *Sender)
{

  if(!ListView1->Selected->Focused ) //revised
   { 
   ListView1->DeleteSelected();
   } 
}
Related