2

我正在尝试对 of 进行子类WindowProc化以在编辑标题TListView后检测 ESC 按键(如果用户取消编辑)。TListViewListViewWndProc 被清楚地调用,但应该检测到的代码参数永远不会获得 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";
}
4

2 回答 2

3

在 C++ 中, 的值LVN_ENDLABELEDEDIT取决于项目的TCHAR_Mapping,可以通过"_TCHAR maps to"配置项在 Project Settings 中更改。默认情况下,在 C++Builder 2009 及更高版本_TCHAR中设置为wchar_t,除非您从早期版本迁移项目,在这种情况下char,默认情况下改为默认设置。

LVN_ENDLABELEDIT是一个宏,当 is 时映射到( LVN_ENDLABELEDITA4294967190),当_TCHARischar时映射到 (4294967120 LVN_ENDLABELEDITW) 。_TCHARwchar_t

检查常量LVN_ENDLABELEDEDITALVN_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);
}
于 2018-05-28T15:36:14.630 回答
2

万一其他人来这里寻找 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)

于 2018-06-30T18:31:16.047 回答