Search code examples
listviewcontextmenuc++builder

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


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.


Solution

  • 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.