分享

InplaceEdit TListView subitem 就地编辑列表视图子项

 quasiceo 2014-08-07
我有3列的ListView和想要编辑的第三列,又名子项目[1]。如果我设置ListView.ReadOnly为True,它可以编辑所选项目的标题。有没有一种简单的方法做事情的子项目?我想远离加上顶部无边界的控制,做编辑。
本文地址 :CodeGo.net/463079/

-------------------------------------------------------------------------------------------------------------------------

1. 您可以使用TEDIT,一个和处理编辑的ListView的子项(在报告模式)OnClick事件的ListView的。 试试这个范例
Const
 USER_EDITLISTVIEW = WM_USER + 666;

type
 TForm1 = class(TForm)
 ListView1: TListView;
 procedure FormCreate(Sender: TObject);
 procedure ListView1Click(Sender: TObject);
 private
 ListViewEditor: TEdit;
 LItem: TListitem;
 procedure UserEditListView( Var Message: TMessage ); message USER_EDITLISTVIEW;
 procedure ListViewEditorExit(Sender: TObject);
 public
 { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

uses
 CommCtrl;
const
 EDIT_COLUMN = 2; //Index of the column to Edit

procedure TForm1.FormCreate(Sender: TObject);
Var
 I : Integer;
 Item : TListItem;
begin
 for I := 0 to 9 do
 begin
 Item:=ListView1.Items.Add;
 Item.Caption:=Format('%d.%d',[i,1]);
 Item.SubItems.Add(Format('%d.%d',[i,2]));
 Item.SubItems.Add(Format('%d.%d',[i,3]));
 end;

 //create the TEdit and assign the OnExit event
 ListViewEditor:=TEdit.Create(Self);
 ListViewEditor.Parent:=ListView1;
 ListViewEditor.OnExit:=ListViewEditorExit;
 ListViewEditor.Visible:=False;
end;

procedure TForm1.ListView1Click(Sender: TObject);
var
 LPoint: TPoint;
 LVHitTestInfo: TLVHitTestInfo;
begin
 LPoint:= listview1.ScreenToClient(Mouse.CursorPos);
 ZeroMemory( @LVHitTestInfo, SizeOf(LVHitTestInfo));
 LVHitTestInfo.pt := LPoint;
 //Check if the click was made in the column to edit
 If (ListView1.perform( LVM_SUBITEMHITTEST, 0, LPARAM(@LVHitTestInfo))<>-1) and ( LVHitTestInfo.iSubItem = EDIT_COLUMN ) Then
 PostMessage( self.Handle, USER_EDITLISTVIEW, LVHitTestInfo.iItem, 0 )
 else
 ListViewEditor.Visible:=False; //hide the TEdit 
end;

procedure TForm1.ListViewEditorExit(Sender: TObject);
begin
 If Assigned(LItem) Then
 Begin
 //assign the vslue of the TEdit to the Subitem
 LItem.SubItems[ EDIT_COLUMN-1 ] := ListViewEditor.Text;
 LItem := nil;
 End;
end;

procedure TForm1.UserEditListView(var Message: TMessage);
var
 LRect: TRect;
begin
 LRect.Top := EDIT_COLUMN;
 LRect.Left:= LVIR_BOUNDS;
 listview1.Perform( LVM_GETSUBITEMRECT, Message.wparam, LPARAM(@LRect) );
 MapWindowPoints( listview1.Handle, ListViewEditor.Parent.Handle, LRect, 2 );
 //get the current Item to edit
 LItem := listview1.Items[ Message.wparam ];
 //set the text of the Edit 
 ListViewEditor.Text := LItem.Subitems[ EDIT_COLUMN-1];
 //set the bounds of the TEdit
 ListViewEditor.BoundsRect := LRect; 
 //Show the TEdit
 ListViewEditor.Visible:=True;
end;


下面的代码xe测试 //编辑框时而出来,时而不出来,尤其是设置了smallimagelist来改变item高度后,
感觉不如上面的//Editable Listview control.txt
2. 我写的示例代码上CodeCentral,显示如何做到这一点。 怎么了TListView的内建的编辑器来编辑子项目 更新: 下面是更新的版本,现在:
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics,
 Controls, Forms, Dialogs, ComCtrls;

type
 TForm1 = class(TForm)
 ListView1: TListView;
 procedure ListView1Editing(Sender: TObject; Item: TListItem; var AllowEdit: Boolean);
 procedure ListView1Edited(Sender: TObject; Item: TListItem; var S: string);
 procedure ListView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 procedure ListView1DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState);
 private
 { Private declarations }
 ColumnToEdit: Integer;
 OldListViewEditProc: Pointer;
 hListViewEditWnd: HWND;
 ListViewEditWndProcPtr: Pointer;
 procedure ListViewEditWndProc(var Message: TMessage);
 public
 { Public declarations }
 constructor Create(Owner: TComponent); override;
 destructor Destroy; override;
 end;

var
 Form1: TForm1;

implementation

uses
 Commctrl;

{$R *.dfm}

type
 TListViewCoord = record
 Item: Integer;
 Column: Integer;
 end;

 TLVGetColumnAt = function(Item: TListItem; const Pt: TPoint): Integer;
 TLVGetColumnRect = function(Item: TListItem; ColumnIndex: Integer; var Rect: TRect): Boolean;
 TLVGetIndexesAt = function(ListView: TCustomListView; const Pt: TPoint; var Coord: TListViewCoord): Boolean;

 // TCustomListViewAccess provides access to the protected members of TCustomListView
 TCustomListViewAccess = class(TCustomListView);

var
 // these will be assigned according to the version of COMCTL32.DLL being used
 GetColumnAt: TLVGetColumnAt = nil;
 GetColumnRect: TLVGetColumnRect = nil;
 GetIndexesAt: TLVGetIndexesAt = nil;

//---------------------------------------------------------------------------
// GetComCtl32Version
//
// Purpose: Helper function to determine the version of CommCtrl32.dll that is loaded.
//---------------------------------------------------------------------------

var
 ComCtl32Version: DWORD = 0;

function GetComCtl32Version: DWORD;
type
 DLLVERSIONINFO = packed record
 cbSize: DWORD;
 dwMajorVersion: DWORD;
 dwMinorVersion: DWORD;
 dwBuildNumber: DWORD;
 dwPlatformID: DWORD;
 end;
 DLLGETVERSIONPROC = function(var dvi: DLLVERSIONINFO): Integer; stdcall;
var
 hComCtrl32: HMODULE;
 lpDllGetVersion: DLLGETVERSIONPROC;
 dvi: DLLVERSIONINFO;
 FileName: array[0..MAX_PATH] of Char;
 dwHandle: DWORD;
 dwSize: DWORD;
 pData: Pointer;
 pVersion: Pointer;
 uiLen: UINT;
begin
 if ComCtl32Version = 0 then
 begin
 hComCtrl32 := GetModuleHandle('comctl32.dll');
 if hComCtrl32 <> 0 then
 begin
  @lpDllGetVersion := GetProcAddress(hComCtrl32, 'DllGetVersion');
  if @lpDllGetVersion <> nil then
  begin
  ZeroMemory(@dvi, SizeOf(dvi));
  dvi.cbSize := SizeOf(dvi);
  if lpDllGetVersion(dvi) >= 0 then
   ComCtl32Version := MAKELONG(Word(dvi.dwMinorVersion), Word(dvi.dwMajorVersion));
  end;
  if ComCtl32Version = 0 then
  begin
  ZeroMemory(@FileName[0], SizeOf(FileName));
  if GetModuleFileName(hComCtrl32, FileName, MAX_PATH) <> 0 then
  begin
   dwHandle := 0;
   dwSize := GetFileVersionInfoSize(FileName, dwHandle);
   if dwSize <> 0 then
   begin
   GetMem(pData, dwSize);
   try
    if GetFileVersionInfo(FileName, dwHandle, dwSize, pData) then
    begin
    pVersion := nil;
    uiLen := 0;
    if VerQueryValue(pData, '\', pVersion, uiLen) then
    begin
     with PVSFixedFileInfo(pVersion)^ do
     ComCtl32Version := MAKELONG(LOWORD(dwFileVersionMS), HIWORD(dwFileVersionMS));
    end;
    end;
   finally
    FreeMem(pData);
   end;
   end;
  end;
  end;
 end;
 end;
 Result := ComCtl32Version;
end;

//---------------------------------------------------------------------------
// Manual_GetColumnAt
//
// Purpose: Returns the column index at the specified coordinates,
// relative to the specified item
//---------------------------------------------------------------------------

function Manual_GetColumnAt(Item: TListItem; const Pt: TPoint): Integer;
var
 LV: TCustomListViewAccess;
 R: TRect;
 I: Integer;
begin
 LV := TCustomListViewAccess(Item.ListView);

 // determine the dimensions of the current column value, and
 // see if the coordinates are inside of the column value

 // get the dimensions of the entire item
 R := Item.DisplayRect(drBounds);

 // loop through all of the columns looking for the value that was clicked on
 for I := 0 to LV.Columns.Count-1 do
 begin
 R.Right := (R.Left + LV.Column[I].Width);
 if PtInRect(R, Pt) then
 begin
  Result := I;
  Exit;
 end;
 R.Left := R.Right;
 end;

 Result := -1;
end;

//---------------------------------------------------------------------------
// Manual_GetColumnRect
//
// Purpose: Calculate the dimensions of the specified column,
// relative to the specified item
//---------------------------------------------------------------------------

function Manual_GetColumnRect(Item: TListItem; ColumnIndex: Integer; var Rect: TRect): Boolean;
var
 LV: TCustomListViewAccess;
 I: Integer;
begin
 Result := False;

 LV := TCustomListViewAccess(Item.ListView);

 // make sure the index is in the valid range
 if (ColumnIndex >= 0) and (ColumnIndex < LV.Columns.Count) then
 begin
 // get the dimensions of the entire item
 Rect := Item.DisplayRect(drBounds);

 // loop through the columns calculating the desired offsets
 for I := 0 to ColumnIndex-1 do
  Rect.Left := (Rect.Left + LV.Column[i].Width);
 Rect.Right := (Rect.Left + LV.Column[ColumnIndex].Width);

 Result := True;
 end;
end;

//---------------------------------------------------------------------------
// Manual_GetIndexesAt
//
// Purpose: Returns the Item and Column indexes at the specified coordinates
//---------------------------------------------------------------------------

function Manual_GetIndexesAt(ListView: TCustomListView; const Pt: TPoint; var Coord: TListViewCoord): Boolean;
var
 Item: TListItem;
begin
 Result := False;

 Item := ListView.GetItemAt(Pt.x, Pt.y);
 if Item <> nil then
 begin
 Coord.Item := Item.Index;
 Coord.Column := Manual_GetColumnAt(Item, Pt);
 Result := True;
 end;
end;

//---------------------------------------------------------------------------
// ComCtl_GetColumnAt
//
// Purpose: Returns the column index at the specified coordinates, relative to the specified item
//---------------------------------------------------------------------------

function ComCtl_GetColumnAt(Item: TListItem; const Pt: TPoint): Integer;
var
 HitTest: LV_HITTESTINFO;
begin
 Result := -1;

 ZeroMemory(@HitTest, SizeOf(HitTest));
 HitTest.pt := Pt;

 if ListView_SubItemHitTest(Item.ListView.Handle, @HitTest) > -1 then
 begin
 if HitTest.iItem = Item.Index then
  Result := HitTest.iSubItem;
 end;
end;

//---------------------------------------------------------------------------
// ComCtl_GetColumnRect
//
// Purpose: Calculate the dimensions of the specified column, relative to the specified item
//---------------------------------------------------------------------------

function ComCtl_GetColumnRect(Item: TListItem; ColumnIndex: Integer; var Rect: TRect): Boolean;
begin
 Result := ListView_GetSubItemRect(Item.ListView.Handle, Item.Index, ColumnIndex, LVIR_BOUNDS, @Rect);
end;

//---------------------------------------------------------------------------
// ComCtl_GetIndexesAt
//
// Purpose: Returns the Item and Column indexes at the specified coordinates
//---------------------------------------------------------------------------

function ComCtl_GetIndexesAt(ListView: TCustomListView; const Pt: TPoint; var Coord: TListViewCoord): Boolean;
var
 HitTest: LV_HITTESTINFO;
begin
 Result := False;

 ZeroMemory(@HitTest, SizeOf(HitTest));
 HitTest.pt := Pt;

 if ListView_SubItemHitTest(ListView.Handle, @HitTest) > -1 then
 begin
 Coord.Item := HitTest.iItem;
 Coord.Column := HitTest.iSubItem;
 Result := True;
 end;
end;

//---------------------------------------------------------------------------
// TForm1 Constructor
//
// Purpose: Form constructor
//---------------------------------------------------------------------------

constructor TForm1.Create(Owner: TComponent);
begin
 inherited Create(Owner);

 // no editing yet
 ColumnToEdit := -1;
 OldListViewEditProc := nil;
 hListViewEditWnd := 0;

 ListViewEditWndProcPtr := MakeObjectInstance(ListViewEditWndProc);
 if ListViewEditWndProcPtr = nil then
 raise Exception.Create('Could not allocate memory for ListViewEditWndProc proxy');

 if GetComCtl32Version >= DWORD(MAKELONG(70, 4)) then
 begin
 @GetColumnAt := @ComCtl_GetColumnAt;
 @GetColumnRect := @ComCtl_GetColumnRect;
 @GetIndexesAt := @ComCtl_GetIndexesAt;
 end else
 begin
 @GetColumnAt := @Manual_GetColumnAt;
 @GetColumnRect := @Manual_GetColumnRect;
 @GetIndexesAt := @Manual_GetIndexesAt;
 end;
end;

//---------------------------------------------------------------------------
// TForm1 Destructor
//
// Purpose: Form destructor
//---------------------------------------------------------------------------

destructor TForm1.Destroy;
begin
 if ListViewEditWndProcPtr <> nil then
 FreeObjectInstance(ListViewEditWndProcPtr);
 inherited Destroy;
end;

//---------------------------------------------------------------------------
// ListViewEditWndProc
//
// Purpose: Custom Window Procedure for TListView's editor window
//---------------------------------------------------------------------------

procedure TForm1.ListViewEditWndProc(var Message: TMessage);
begin
 if Message.Msg = WM_WINDOWPOSCHANGING then
 begin
 // this inline editor has a bad habit of re-positioning itself
 // back on top of the Caption after every key typed in,
 // so let's stop it from moving
 with TWMWindowPosMsg(Message).WindowPos^ do flags := flags or SWP_NOMOVE;
 Message.Result := 0;
 end else
 begin
 // everything else
 Message.Result := CallWindowProc(OldListViewEditProc, hListViewEditWnd,
  Message.Msg, Message.WParam, Message.LParam);
 end;
end;

//---------------------------------------------------------------------------
// ListView1DrawItem
//
// Purpose: Handler for the TListView::OnDrawItem event
//---------------------------------------------------------------------------

procedure TForm1.ListView1DrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
 LV: TCustomListViewAccess;
 R: TRect;
 P: TPoint;
 I: Integer;
 S: String;
begin
 LV := TCustomListViewAccess(Sender);

 // erase the entire item to start fresh
 R := Item.DisplayRect(drBounds);
 LV.Canvas.Brush.Color := LV.Color;
 LV.Canvas.FillRect(R);

 // see if the mouse is currently held down, and if so update the marker as needed
 if (GetKeyState(VK_LBUTTON) and $8000) <> 0 then
 begin
 // find the mouse cursor onscreen, convert the coordinates to client
 // coordinates on the list view
 GetCursorPos(P);
 ColumnToEdit := GetColumnAt(Item, LV.ScreenToClient(P));
 end;

 // loop through all of the columns drawing each column
 for I := 0 to LV.Columns.Count-1 do
 begin
 // determine the dimensions of the current column value
 if not GetColumnRect(Item, I, R) then
  Continue;

 // mimic the default behavior by only drawing a value as highlighted if
 // the entire item is selected, the particular column matches the marker,
 // and the ListView is not already editing
 if Item.Selected and (I = ColumnToEdit) and (not LV.IsEditing) then
 begin
  LV.Canvas.Brush.Color := clHighlight;
  LV.Canvas.Font.Color := clHighlightText;
 end else
 begin
  LV.Canvas.Brush.Color := LV.Color;
  LV.Canvas.Font.Color := LV.Font.Color;
 end;

 LV.Canvas.FillRect(R);

 // draw the column's text
 if I = 0 then
  S := Item.Caption
 else
  S := Item.SubItems[I-1];

 LV.Canvas.TextRect(R, R.Left + 2, R.Top, S);
 end;
end;

//---------------------------------------------------------------------------
// ListView1Edited
//
// Purpose: Handler for the TListView::OnEdited event
//---------------------------------------------------------------------------

procedure TForm1.ListView1Edited(Sender: TObject; Item: TListItem; var S: string);
begin
 // ignore the Caption, let it do its default handling
 if ColumnToEdit <= 0 then Exit;

 // restore the previous window procedure for the inline editor
 if hListViewEditWnd <> 0 then
 begin
 SetWindowLongPtr(hListViewEditWnd, GWL_WNDPROC, LONG_PTR(OldListViewEditProc));
 hListViewEditWnd := 0;
 end;

 // assign the new text to the subitem being edited
 Item.SubItems[ColumnToEdit-1] := S;

 // prevent the default behavior from updating the Caption as well
 S := Item.Caption;
end;

//---------------------------------------------------------------------------
// ListView1Editing
//
// Purpose: Handler for the TListView::OnEditing event
//---------------------------------------------------------------------------

procedure TForm1.ListView1Editing(Sender: TObject; Item: TListItem; var AllowEdit: Boolean);
var
 Wnd: HWND;
 R: TRect;
begin
 // ignore the Caption, let it do its default handling
 if ColumnToEdit <= 0 then Exit;

 // get the inline editor's handle
 Wnd := ListView_GetEditControl(ListView1.Handle);
 if Wnd = 0 then Exit;

 // determine the dimensions of the subitem being edited
 if not GetColumnRect(Item, ColumnToEdit, R) then Exit;

 // move the inline editor over the subitem
 MoveWindow(Wnd, R.Left, R.Top - 2, R.Right-R.Left, (R.Bottom-R.Top) + 4, TRUE);

 // update the inline editor's text with the subitem's text rather than the Caption
 SetWindowText(Wnd, PChar(Item.SubItems[ColumnToEdit-1]));

 // subclass the inline editor so we can catch its movements
 hListViewEditWnd := Wnd;
 OldListViewEditProc := Pointer(GetWindowLongPtr(Wnd, GWL_WNDPROC));
 SetWindowLongPtr(Wnd, GWL_WNDPROC, LONG_PTR(ListViewEditWndProcPtr));
end;

//---------------------------------------------------------------------------
// ListView1MouseDown
//
// Purpose: Handler for the TListView::OnMouseDown event
//---------------------------------------------------------------------------

procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
 Coord: TListViewCoord;
begin
 if GetIndexesAt(ListView1, Point(X, Y), Coord) then
 begin
 if Coord.Column <> ColumnToEdit then
 begin
  // update the marker
  ColumnToEdit := Coord.Column;

  // cancel the editing so that the listview won't go into
  // its edit mode immediately upon clicking the new item
  ListView1.Items[Coord.Item].CancelEdit;

  // update the display with a new highlight selection
  ListView1.Invalidate;
 end;
 end else
 ColumnToEdit := -1;
end;

end.

//Editable Listview control.txt
Editable Listview control
Posted by zairon on November 6, 2007 Posted in: General, Programming. 5 Comments
Few days ago I started renewing my PE editor’s gui, I wanted to replace some edit box controls with a listview control. Everything was going well until I had to edit the value inside a cell. With the original listview control you can change the text of the first subitem of a row only, but I would like to edit every single subitem. How can I solve the problem? I didn’t want to waste time solving the problem so I decided to take a look at the usual programming places starting from Code Project. Hm, nothing. I’m not so good in searching information through the net, but seems like there are working samples on mfc, .net and vb only. No win32 programming stuff… Well, I decided to give it a try subclassing the control.
I have never subclass-ed a control before, it’s my first try. I don’t know if there’s a better approach. I don’t even know if it’s the correct way to solve the problem, but it seems to works well. Let’s start.

The steps to follow are:
1. Create an edit box that will be used to insert the new text
2. Set the new window procedure able to handle edit control’s messages
3. Apply/abort text modification

I use VS creating a win32 project. Add a listview control to your dialog setting “Edit labels” to FALSE. If you set the option to TRUE the OS will handle subitem modification, I prefer to avoid this behaviour.

The idea is to change the subitem’s text when a double click occours. I catch the event in the main window procedure calling the function (named SubClass_ListView_Editable) which subclasses the control.

The first step consists of creating the edit box over the clicked subitem. To create the edit box I need to know where to put it. LVM_GETSUBITEMRECT returns information about the rectangle for a subitem of a listview control. With this information I can create the new control:

ListView_GetSubItemRect(hListView, _lParam->iItem, _lParam->iSubItem, LVIR_LABEL, &r);
// Time to create the new edit box
hEditable = CreateWindowEx(0, "EDIT", "Edit me", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_MULTILINE, r.left, r.top, r.right-r.left, r.bottom-r.top, _lParam->hdr.hwndFrom, NULL, hInst, 0);

“r” is defined as a RECT structure:

typedef struct _RECT {
LONG left; // x-coordinate of the upper-left corner of the rectangle
LONG top; // y-coordinate of the upper-left corner of the rectangle
LONG right; // x-coordinate of the lower-right corner of the rectangle
LONG bottom; // y-coordinate of the lower-right corner of the rectangle
} RECT, *PRECT;

As you can see I use “r” inside CreateWindowEx function specifying the coordinates of the new control.
The third parameter of CreateWindowEx is the text that will be shown in the control. I use a static text but you can leave it blank or display the subitem’s text, it’s up to you. Now, the new control has been created and I’m going to set some features:

SendMessage(hEditable, EM_LIMITTEXT, 8, 0); // It accepts no more than 8 chars
SendMessage(hEditable, EM_SETSEL, 0, 8); // Text selected
SetFocus(hEditable); // Focus to the new box

If you don’t need a particular behaviour (limit text, accept only numbers…) you can avoid the first two calls but I think the third one is useful, it gives the focus to the new edit box.

The control is complete, I have to add the new window procedure. This can be done using SetWindoLong function:

LONG SetWindowLong(
HWND hWnd, // Handle of the new edit control
int nIndex, // The attribute to change
LONG dwNewLong // The new value
);

The function changes an attribute of a specified window, in this case I’m going to change the address of the dialog procedure. The aim is to add a new window procedure for handling edit box’s messages only. I’ll pass over all the other messages forwarding them towards the old window procedure.

wpOld = (WNDPROC)SetWindowLong(hEditable, GWL_WNDPROC, SubClass_ListView_WndProc);
SetProp(hEditable, "WP_OLD", (HANDLE)wpOld);


SubClass_ListView_WndProc represents the new dialog procedure.
I have to save the address of the original window procedure because I have to restore it when I’ll destroy the edit box. To save the address I use SetProp function, but if you prefer you can use global variables. To end this piece of code I save some more useful information: row and column of the subitem to change:

SetProp(hEditable, "ITEM", (HANDLE)_lParam->iItem);
SetProp(hEditable, "SUBITEM", (HANDLE)_lParam->iSubItem);


Which kind of messages will I have to catch? WM_KEYDOWN and WM_DESTROY only, all the other messages are passed to the original window procedure in this way:

return CallWindowProc((WNDPROC)GetProp(hEditable, "WP_OLD"), hwnd, uMsg, wParam, lParam);

I catch WM_KEYDOWN because I have to handle ENTER ans ESC key. When you hit ENTER the text will be saved in the subitem, and when you click ESC the operation will be aborted:

case WM_KEYDOWN:
if (LOWORD(wParam) == VK_RETURN)
{
...
// Item and suibtem to change
LvItem.iItem = GetProp(hEditable, "ITEM");
LvItem.iSubItem = GetProp(hEditable, "SUBITEM");
// Where to store the new text
LvItem.pszText = text;
// Get new text and set it in the subitem
GetWindowText(hEditable, text, sizeof(text));
SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)GetProp(hEditable, "ITEM"), (LPARAM)&LvItem);
DestroyWindow(hEditable);
}
else if (LOWORD(wParam) == VK_ESCAPE)
DestroyWindow(hEditable);
break;

If you press ESC the edit box will be destroyed without changing the subitem’s text.
When ENTER is pressed I simply get the text storing it in the subitem. After that I can destroy the edit box.
There’s something more to say about VK_RETURN. Look at CreateWindowEx parameters, there’s a ES_MULTILINE value. The value is necessary otherwise the application refuses to catch ENTER.
The last thing I check in the new window procedure is WM_DESTROY message, I simply remove the saved properties and then I restore the original window procedure calling SetWindowLong again.

What about mouse click when I’m changing the subitem’s value? It’s like VK_ESCAPE key, I remove the edit box aborting the operation. See the attached source code for details.

The picture represents the subclassing method in action:



The code can be optimized for sure, just fix/change/remove/add everything you need. Feel free to post your comment/suggestion/criticism here.
Download the VS project from here





    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多