Relating to Sub classing a TListView relates also to Prevent action in TListView's context menu when in edit mode
My subclassed ListView captures the ESC key (with Remy's help) and now I managed to capture the Del key when editing, without the side effects of having a menu item's shortcut preventing the Del key from working in the ListView's edit control.
Calling ListView_SetView(ListViewEx1->Handle, LV_VIEW_TILE); works fine on TListView, but not in my TListViewEx. Any ideas would be great. - FIXED
.cpp of TListViewEx
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TListViewEx.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TListViewEx *)
{
new TListViewEx(NULL);
}
//---------------------------------------------------------------------------
__fastcall TListViewEx::TListViewEx(TComponent* Owner)
: TListView(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TListViewEx::Click()
{
TListView::Click();
}
//---------------------------------------------------------------------------
void __fastcall TListViewEx::WMGetDlgCode(TMessage &msg)
{
TCustomListView::Dispatch(&msg);
msg.Result |= DLGC_WANTCHARS;
}
//---------------------------------------------------------------------------
void __fastcall TListViewEx::CNKeyDown(TMessage &Message)
{
if (Message.WParam == VK_DELETE)
{
if(FOnWantEditEvent)
{
FEdit = ListView_GetEditControl(Handle);
OnWantEditEvent(this, FKey);
}
}
TListView::Dispatch(&Message);
}
//---------------------------------------------------------------------------
void __fastcall TListViewEx::SetView(int view)
{
ListView_SetView(Handle, view);
}
//---------------------------------------------------------------------------
void __fastcall TListViewEx::CNNotify(Winapi::Messages::TWMNotify &Message)
{
// TListView::Dispatch(&Message);
TListView::Dispatch(&Message);
if (Message.NMHdr->code == LVN_ENDLABELEDITA || Message.NMHdr->code == LVN_ENDLABELEDITW)
{
NMLVDISPINFO *plvdi = reinterpret_cast<NMLVDISPINFO*>(Message.NMHdr);
if ((plvdi->item.pszText == NULL) && (plvdi->item.iItem != -1) && (FOnEditCancel != NULL))
{
// ideally, you should be using TCustomListView::GetItem(LVITEM)
// to determine the TListItem affected, but that method is private
// and not accessible to descendants, which is all the more reason
// why Embarcadero needs to fix this in the native TListView instead...
TListItem *item;
if (plvdi->item.mask & LVIF_PARAM)
item = reinterpret_cast<TListItem*>(plvdi->item.lParam);
else // TODO: handle OwnerData=true ...
item = this->Items->Item[plvdi->item.iItem];
FOnEditCancel(this, item);
}
}
}
//---------------------------------------------------------------------------
namespace Tlistviewex
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TListViewEx)};
RegisterComponents(L"Samples", classes, 0);
}
}
//---------------------------------------------------------------------------
.h
//---------------------------------------------------------------------------
#ifndef TListViewExH
#define TListViewExH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <Vcl.ComCtrls.hpp>
#include <Vcl.Controls.hpp>
//---------------------------------------------------------------------------
typedef void __fastcall (__closure *TOnEditCancel)(TObject* Sender, TListItem* item);
typedef void __fastcall (__closure *TOnWantEditEvent)(TObject* Sender, WORD &Key);
class PACKAGE TListViewEx : public TListView
{
private:
TOnEditCancel FOnEditCancel;
TOnWantEditEvent FOnWantEditEvent;
HWND FEdit;
MESSAGE void __fastcall WMGetDlgCode(TMessage &msg);
MESSAGE void __fastcall CNNotify(Winapi::Messages::TWMNotify &Message);
MESSAGE void __fastcall CNKeyDown(TMessage &Message);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_GETDLGCODE, TMessage, WMGetDlgCode)
VCL_MESSAGE_HANDLER(CN_NOTIFY, TWMNotify, CNNotify);
VCL_MESSAGE_HANDLER(CN_KEYDOWN, TMessage, CNKeyDown);
END_MESSAGE_MAP(TListView);
protected:
DYNAMIC void __fastcall Click();
public:
__property HWND Edit = {read = FEdit};
__fastcall TListViewEx(TComponent* Owner);
void __fastcall SetView(int view);
__published:
__property TOnEditCancel OnEditCancel = {read = FOnEditCancel, write = FOnEditCancel};
__property TOnWantEditEvent OnWantEditEvent = {read = FOnWantEditEvent, write = FOnWantEditEvent};
};
//---------------------------------------------------------------------------
#endif
TForm implementation of FOnWantEditEvent, based on code by Martin Nijhoff:
.cpp
void __fastcall TForm3::ListViewEx1WantEditEvent(TObject *Sender, Word &Key)
{
switch(Key)
{
case VK_DELETE:
{
if(ListViewEx1->Edit)
{
UINT Scan = MapVirtualKey(VK_DELETE, MAPVK_VK_TO_VSC); // Get scan code of Del key.
SendMessage(ListViewEx1->Edit, WM_KEYDOWN, VK_DELETE, 0x00000001 | Scan << 16); // Simulate Del keypress in edit window.
SendMessage(ListViewEx1->Edit, WM_KEYUP, VK_DELETE, 0xC0000001 | Scan << 16);
}
}
break;
}
}
//-------------------------------------------------------------------------
void __fastcall TForm3::Delete1Click(TObject *Sender)
{
if(!ListViewEx1->IsEditing())
ListViewEx1->DeleteSelected();
ViewTile();
}
