TListView 检测 ESC 或不变的编辑
TListView detecting ESC or unchanged editing
我正在尝试子类化 TListView
的 WindowProc
以在编辑 TListView
标题后检测 ESC 键按下(如果用户取消编辑)。 ListViewWndProc 被清楚地调用,但应该检测的代码参数永远不会获得 LVN_ENDLABELEDIT 值。为什么评论部分永远不会被调用?我看不到错误,它应该正在发生。
TWndMethod OldWndProc;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
OldWndProc = ListView1->WindowProc;
ListView1->WindowProc = ListViewWndProc;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListViewWndProc(TMessage &Message)
{
if (Message.Msg == CN_NOTIFY)
{
LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);
if (pnmh->code == LVN_ENDLABELEDIT) // UPDATE: if LVN_ENDLABELEDIT is replaced with 4294967120 it works
{
// !!! THE FOLLOWING NEVER HAPPENS !!!
// UPDATE: Looks like LVN_ENDLABELEDIT is incorrectly defined in C++ Builder 2010
// if LVN_ENDLABELEDIT is replaced with 4294967120 the code works
LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
if (pdi->item.pszText == NULL)
{
Edit1->Text = "Cancelled";
return;
}
}
}
OldWndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Editing(TObject *Sender, TListItem *Item, bool &AllowEdit)
{
Edit1->Text = "Editing";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, UnicodeString &S)
{
Edit1->Text = "Done";
}
在 C++ 中,LVN_ENDLABELEDEDIT
的值取决于项目的 TCHAR_Mapping,可以通过 "_TCHAR maps to"
配置项在项目设置中更改。默认情况下,_TCHAR
在 C++Builder 2009 及更高版本中设置为 wchar_t
,除非您从早期版本迁移项目,在这种情况下,它默认设置为 char
。
LVN_ENDLABELEDIT
是一个宏,当 _TCHAR
为 char
时映射到 LVN_ENDLABELEDITA
(4294967190),当 [=] 时映射到 LVN_ENDLABELEDITW
(4294967120) 13=] 是 wchar_t
.
检查常量 LVN_ENDLABELEDEDITA
和 LVN_ENDLABELEDEDITW
,就像在 Delphi 源代码中所做的那样,应该没问题。
void __fastcall TForm1::ListViewWndProc(TMessage &Message)
{
if (Message.Msg == CN_NOTIFY)
{
LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);
if ((pnmh->code == LVN_ENDLABELEDITA) || (pnmh->code == LVN_ENDLABELEDITW))
{
LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
if (pdi->item.pszText == NULL)
{
Edit1->Text = "Cancelled";
return;
}
}
}
OldWndProc(Message);
}
以防其他人到这里来寻找 Delphi 中的解决方案,我刚刚翻译了 Kerem D 的代码:
constructor TForm1.Create(_Owner: TComponent);
begin
inherited;
OldWndProc = ListView1.WindowProc;
ListView1.WindowProc = ListViewWndProc;
end;
procedure TForm1.ListViewWndProc(var _Message: TMessage);
var
LvDispInfo: PLVDispInfo; // declared in CommCtrl
Code: Integer;
begin
if _Message.Msg = CN_NOTIFY then begin
Code := PNMHdr(_Message.lParam).Code;
if (Code = LVN_ENDLABELEDITA) or (Code = LVN_ENDLABELEDITW) then begin
LvDispInfo := PLVDispInfo(_Message.lParam);
if LvDispInfo.Item.pszText = nil then begin
Edit1.Text := 'Cancelled';
Exit; //==>
end;
end;
end;
OldWndProc(_Message);
end;
它适用于 Delphi 6 到 10.2(在 GExperts 中使用)
我正在尝试子类化 TListView
的 WindowProc
以在编辑 TListView
标题后检测 ESC 键按下(如果用户取消编辑)。 ListViewWndProc 被清楚地调用,但应该检测的代码参数永远不会获得 LVN_ENDLABELEDIT 值。为什么评论部分永远不会被调用?我看不到错误,它应该正在发生。
TWndMethod OldWndProc;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
OldWndProc = ListView1->WindowProc;
ListView1->WindowProc = ListViewWndProc;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListViewWndProc(TMessage &Message)
{
if (Message.Msg == CN_NOTIFY)
{
LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);
if (pnmh->code == LVN_ENDLABELEDIT) // UPDATE: if LVN_ENDLABELEDIT is replaced with 4294967120 it works
{
// !!! THE FOLLOWING NEVER HAPPENS !!!
// UPDATE: Looks like LVN_ENDLABELEDIT is incorrectly defined in C++ Builder 2010
// if LVN_ENDLABELEDIT is replaced with 4294967120 the code works
LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
if (pdi->item.pszText == NULL)
{
Edit1->Text = "Cancelled";
return;
}
}
}
OldWndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Editing(TObject *Sender, TListItem *Item, bool &AllowEdit)
{
Edit1->Text = "Editing";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1Edited(TObject *Sender, TListItem *Item, UnicodeString &S)
{
Edit1->Text = "Done";
}
在 C++ 中,LVN_ENDLABELEDEDIT
的值取决于项目的 TCHAR_Mapping,可以通过 "_TCHAR maps to"
配置项在项目设置中更改。默认情况下,_TCHAR
在 C++Builder 2009 及更高版本中设置为 wchar_t
,除非您从早期版本迁移项目,在这种情况下,它默认设置为 char
。
LVN_ENDLABELEDIT
是一个宏,当 _TCHAR
为 char
时映射到 LVN_ENDLABELEDITA
(4294967190),当 [=] 时映射到 LVN_ENDLABELEDITW
(4294967120) 13=] 是 wchar_t
.
检查常量 LVN_ENDLABELEDEDITA
和 LVN_ENDLABELEDEDITW
,就像在 Delphi 源代码中所做的那样,应该没问题。
void __fastcall TForm1::ListViewWndProc(TMessage &Message)
{
if (Message.Msg == CN_NOTIFY)
{
LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(Message.LParam);
if ((pnmh->code == LVN_ENDLABELEDITA) || (pnmh->code == LVN_ENDLABELEDITW))
{
LV_DISPINFO *pdi = reinterpret_cast<LV_DISPINFO*>(Message.LParam);
if (pdi->item.pszText == NULL)
{
Edit1->Text = "Cancelled";
return;
}
}
}
OldWndProc(Message);
}
以防其他人到这里来寻找 Delphi 中的解决方案,我刚刚翻译了 Kerem D 的代码:
constructor TForm1.Create(_Owner: TComponent);
begin
inherited;
OldWndProc = ListView1.WindowProc;
ListView1.WindowProc = ListViewWndProc;
end;
procedure TForm1.ListViewWndProc(var _Message: TMessage);
var
LvDispInfo: PLVDispInfo; // declared in CommCtrl
Code: Integer;
begin
if _Message.Msg = CN_NOTIFY then begin
Code := PNMHdr(_Message.lParam).Code;
if (Code = LVN_ENDLABELEDITA) or (Code = LVN_ENDLABELEDITW) then begin
LvDispInfo := PLVDispInfo(_Message.lParam);
if LvDispInfo.Item.pszText = nil then begin
Edit1.Text := 'Cancelled';
Exit; //==>
end;
end;
end;
OldWndProc(_Message);
end;
它适用于 Delphi 6 到 10.2(在 GExperts 中使用)