unit ListEdit; interface uses KOL, Windows, Messages, objects; const WM_JUSTFREE = WM_USER + 51; WM_EDITFREE = WM_USER + 52; WM_DBLCLICK = WM_USER + 53; WM_ROWCHANG = WM_USER + 54; type PListEdit =^TListEdit; TKOLListEdit = PControl; TListEdit = object(Tobj) EList: PList; Enter: boolean; LView: PControl; TabSave: boolean; TabStrt: boolean; OldWind: longint; NewWind: longint; CurEdit: integer; destructor destroy; virtual; procedure SetEvents(LV: PControl); procedure NewWndProc(var Msg: TMessage); procedure LVPaint; procedure LVDblClk; procedure LVChange(Store: boolean); procedure PostFree(var Key: integer); procedure EDChar(Sender: PControl; var Key: integer; Sh: Cardinal); procedure EDPres(Sender: PControl; var Key: integer; Sh: Cardinal); procedure EDentr(Sender: PObj); end; function NewListEdit(AParent: PControl; Style: TListViewStyle; Options: TListViewOptions; ImageListSmall, ImageListNormal, ImageListState: PImageList): PControl; implementation function NewListEdit; var p: PListEdit; begin Result := NewListView(AParent, Style, Options, ImageListSmall, ImageListNormal, ImageListState); Result.CreateWindow; New(p, create); AParent.Add2AutoFree(p); p.LView := Result; p.SetEvents(PControl(Result)); end; destructor TListEdit.destroy; begin LVChange(False); EList.Free; SetWindowLong(LView.Handle, GWL_WNDPROC, OldWind); FreeObjectInstance(Pointer(NewWind)); inherited; end; procedure TListEdit.SetEvents; begin EList := NewList; Enter := False; TabStrt := False; OldWind := GetWindowLong(LV.Handle, GWL_WNDPROC); NewWind := LongInt(MakeObjectInstance(NewWndProc)); SetWindowLong(LV.Handle, GWL_WNDPROC, NewWind); end; procedure TListEdit.NewWndProc; var e: boolean; begin e := EList.Count > 0; case Msg.Msg of WM_LBUTTONDOWN: begin LVChange(True); CurEdit := 0; if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0); end; WM_LBUTTONDBLCLK: begin LVDblClk; end; WM_KEYDOWN: begin if Msg.WParam = 13 then begin LVDblClk; end else { if Msg.WParam = 27 then begin LVChange(False); end else begin LVChange(True); if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0); end;} end; WM_NCPAINT: begin LVPaint; end; WM_JUSTFREE: begin LVChange(Msg.WParam <> 27); end; WM_EDITFREE: begin LVChange(Msg.WParam <> 27); if e then PostMessage(LView.Handle, WM_DBLCLICK, 0, 0); end; WM_DBLCLICK: begin LVDblClk; end; WM_PAINT: begin LVPaint; end; end; Msg.Result := CallWindowProc(Pointer(OldWind), LView.Handle, Msg.Msg, Msg.wParam, Msg.lParam); end; procedure TListEdit.LVPaint; var i: integer; r: TRect; l: integer; e: PControl; p: TPoint; begin with LView^ do begin SendMessage(Handle, WM_SETFONT, Font.Handle, 0); l := 0; p := LVItemPos[0]; for i := 0 to EList.Count - 1 do begin r := LVItemRect(LVCurItem, lvipBounds); r.Left := l + p.X; r.Right := l + LVColWidth[i] + p.X; Dec(r.Top); Inc(r.Bottom); e := EList.Items[i]; e.BoundsRect := r; l := l + LVColWidth[i]; end; end; end; procedure TListEdit.LVDblClk; var i: integer; e: PControl; r: TRect; l: integer; a: PControl; p: TPoint; o: TPoint; begin with LView^ do begin if EList.Count <> 0 then LVChange(True); if enter then exit; enter := true; l := 0; a := nil; GetCursorPos(p); p := Screen2Client(p); o := LVItemPos[0]; for i := 0 to LVColCount - 1 do begin r := LVItemRect(LVCurItem, lvipBounds); r.Left := l + o.X; r.Right := l + LVColWidth[i] + o.X; l := l + LVColWidth[i]; Dec(r.Top); Inc(r.Bottom); e := NewEditBox(LView, []); EList.Add(e); e.BoundsRect := r; e.DoubleBuffered := True; e.Tabstop := True; e.Font.FontHeight := LView.Font.FontHeight; e.Font.FontCharset := 204; e.Text := LVItems[LVCurItem, i]; e.OnKeyDown := EDChar; e.OnKeyUp := EDPres; e.OnEnter := EDEntr; e.Show; if a = nil then a := e; if (CurEdit <> 0) then if (EList.Count = CurEdit) then a := e else else if (r.Left <= p.x) and (r.Right >= p.x) then a := e; end; if a <> nil then a.Focused := True; TabSave := TabStop; TabStop := False; TabStrt := True; enter := false; end; end; procedure TListEdit.LVChange; var e: PControl; i: integer; g: boolean; begin with LView^ do begin if enter then exit; enter := true; g := False; for i := 0 to EList.Count - 1 do begin e := EList.Items[i]; if Store then begin g := g or (LVItems[LVCurItem, i] <> e.Text); LVItems[LVCurItem, i] := e.Text; end; if e.Focused then CurEdit := i + 1; e.Free; end; EList.Clear; enter := false; if TabStrt then TabStop := TabSave; if g then SendMessage(Parent.Handle, WM_ROWCHANG, LVCurItem, 0); end; end; procedure TListEdit.PostFree; begin with LView^ do begin if Key = 27 then PostMessage(Handle, WM_JUSTFREE, key, 0); if Key = 13 then PostMessage(Handle, WM_EDITFREE, key, 0); if ((key = 40) and (LView.LVCurItem < LView.LVCount - 1)) or ((key = 38) and (LView.LVCurItem > 0)) then begin PostMessage(Handle, WM_EDITFREE, key, 0); PostMessage(Handle, wm_keydown, Key, 0); PostMessage(Handle, wm_keyup, Key, 0); end; end; end; procedure TListEdit.EDChar; begin case key of 13, 27, 38, 40: PostFree(key); end; end; procedure TListEdit.EDPres; begin case key of 38, 40: key := 0; end; end; procedure TListEdit.EDentr; begin PControl(Sender).SelectAll; end; end.