Delphi在Listview中加入Edit控件

Delphi在Listview中加入Edit控件 或者 使用该控件 StringGrid http://blog.sina.com.cn/s/blog_60020ca50100rgtn.html
  2010-07-15 作者:李海彬   
   Listview是一个非常有用的控件,我们常常将大量的数据(如数据库里的数据)导入到Listview中,有的时候我们需要编辑Listview里的数据,而它并不提供编辑的功能,怎么样才能使它具有编辑功能呢?你可以试试下面这种方法。
  
   首先在FORM1中放置一个Listview控件和一个Eeit控件。Edit控件有什么用?当然是用来编辑Listview里的内容,程序的想法是这样的:当鼠标点击了Listview控件后,根据鼠标位置将Edit控件放置到Listview对应的Column里,将对应Item里的内容读入Edit中,在Edit中编辑好后,再将Edit编辑过的信息回写到Item中。
  
   代码如下:
  
  unit Unit1;
  
  interface
  
  uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
   Dialogs, ComCtrls, CommCtrl, StdCtrls, ImgList;
  
  type
   TForm1 = class(TForm)
   ListView1: TListView;
   Edit1: TEdit;
   procedure Edit1KeyDown(Sender: TObject; var Key: Word;
   Shift: TShiftState);
   procedure Edit1Change(Sender: TObject);
   procedure ListView1MouseDown(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
   procedure FormCreate(Sender: TObject);
   procedure ListView1ColumnDagged(Sender: TObject);
   private
   { Private declarations }
  
   FListViewWndProc1: TWndMethod;
   procedure ListViewWndProc1(var Msg: TMessage);
   public
   { Public declarations }
   end;
  
  const MaxColumns=3 ; // 总Columns-1
  var
   Form1: TForm1;
   edtcol:integer; //记录EDIT1在Columns中的位置,1- MaxColumns;
   editem:Tlistitem;
  implementation
  
  {$R *.dfm}
  
  //拦截LISTVIEW1消息
  procedure TForm1.ListViewWndProc1(var Msg: TMessage);
  var IsNeg : Boolean;
  begin
   try
   ShowScrollBar(ListView1.Handle, SB_HORZ, false);
  
   //拖动Listview1滚动条时,将EDIT1隐藏起来
   if(msg.Msg =WM_VSCROLL) or (msg.Msg=WM_MOUSEWHEEL ) then edit1.Visible :=false;
   if Msg.Msg = WM_MOUSEWHEEL then
   begin
   if listview1.Selected=nil then exit;
   IsNeg := Short(msg.WParamHi) < 0;
   listview1.SetFocus ;
   if IsNeg then
   SendMessage(edit1.Handle, WM_KEYDOWN, VK_down, 0)
   else
   SendMessage(edit1.Handle, WM_KEYDOWN, VK_up, 0);
   end
   else
   FListViewWndProc1(Msg);
   except
   end;
  end;
  
  //拦截EDIT的按键消息,对上、下、左、右方向键进行处理------
  procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word;
   Shift: TShiftState);
  var item:tlistitem;
   ix,lt,i:integer;
   rect:Trect;
  begin
  TRY
   //----对上、下、左、右方向键进行处理-----------------
   if(key<>VK_DOWN) AND (KEY<>VK_UP) AND (KEY<>VK_RIGHT) AND (KEY<>VK_LEFT) THEN EXIT;
   IF(KEY=VK_RIGHT) THEN //键盘右键
   BEGIN
   //按下键盘右键后,判断光标位置是否处于最右边,如果不在最右边,不作处理 EXIT
   if length(edit1.Text)>edit1.SelStart then exit;
   item:=listview1.Selected;
   //计算edit1位于哪个Columns,如果<最大Columns,+1,否则=1,即转到最左边
  
   if(edtcol
  
   //从 edtcol值计算出 Columns的位置(Left,width),EDIT1按此设置
   lt:=0;
   for i:=0 to edtcol-1 do lt:=lt+listview1.Columns[i].Width;
   edit1.Left:=lt+1;
   edit1.Width :=listview1.Columns[edtcol].Width;
   END;
   IF(KEY=VK_left) THEN //键盘左键
   BEGIN
   if edit1.SelStart<>0 then exit;
   item:=listview1.Selected;
   if(edtcol>0) then edtcol:=edtcol-1 else edtcol:=MaxColumns;
   lt:=0;
   for i:=0 to edtcol-1 do lt:=lt+listview1.Columns[i].Width;
   edit1.Left:=lt+1;
   edit1.Width :=listview1.Columns[edtcol].Width;
   END;
   if(key=VK_DOWN ) then //键盘下键
   begin
   item:=listview1.Selected;
   if item=nil then exit;
   ix:=item.Index;
   if ix>=listview1.Items.Count-1 then exit;
   SendMessage(listview1.Handle, WM_KEYDOWN, VK_down, 0)
   end;
   if(key=VK_UP) then //键盘上键
   begin
   item:=listview1.Selected;
   if item=nil then exit;
   ix:=item.Index;
   if ix<1 then exit;
   SendMessage(listview1.Handle, WM_KEYDOWN, VK_up, 0)
   end;
   listview1.ItemFocused :=listview1.Selected;
   item:=listview1.Selected ;
   edit1.Visible :=false;
   rect:=item.DisplayRect(drSelectBounds);
   edit1.SetBounds(edit1.left,rect.Top-1,edit1.Width,rect.Bottom-rect.Top+2);
   IF edtcol>0 then edit1.Text:=item.SubItems[edtcol-1]
   else edit1.Text:=item.Caption ;
   edit1.Visible:=true;
   edit1.SetFocus;
  
  EXCEPT
  END;
  end;
  
  
  //编辑控件内容改变后,保存改变到Listview1对应位置
  procedure TForm1.Edit1Change(Sender: TObject);
  begin
  TRY
   if not edit1.Visible then exit;
   listview1.Selected.SubItems[edtcol-1]:=edit1.Text;
  EXCEPT
  END;
  end;
  //在LISTVIEW1上按下鼠标
  procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
  var
   rect:Trect;
   p:tpoint;
   wtmp,i:integer;
  begin
  TRY
   //显示编辑控件
   edit1.Visible:=false;
   //根据鼠标位置,得到所对应行的LISTITEM
   editem:=listview1.GetItemAt(x,y);
   if editem<>nil then
   begin
   //根据鼠标位置,计算出是哪个 Columns.
   p:=editem.Position;
   wtmp:=p.X;
   for i:=0 to listview1.Columns.Count-1 do
   if (x>wtmp) and (x<(wtmp+listview1.Column[i].Width))
   then break //找到对应的Columns,打断退出,I确定.
   else inc(wtmp,listview1.Column[i].Width);
   //根据I的值,取得 Columns的对应位置。在对应位置按其它的SIZE放EDIT1。
   edtcol:=i;
   rect:=editem.DisplayRect(drSelectBounds);
   edit1.SetBounds(wtmp-1,rect.Top-1,listview1.Column[i].Width+1,rect.Bottom-rect.Top+2);
   if edtcol>0 then edit1.Text:=editem.SubItems[i-1]
   else edit1.Text:=editem.Caption;
   edit1.Visible:=true;
   edit1.SetFocus;
   end;
  EXCEPT
  END;
  end;
  //初始化,加入测试数据.
  procedure TForm1.FormCreate(Sender: TObject);
  var item:tlistitem;
   i:integer;
  begin
  
   //将edit1的父亲选为LISTVIEW1,用以响应LISTVIEW1消息
  
   edit1.parent:=Listview1;
  
   //拦载LISTVIEW1鼠标消息
  
   FListViewWndProc1:=ListView1.WindowProc;
   ListView1.WindowProc := ListViewWndProc1;
   
  
   for i:=0 to 10 do
   begin
   item:=listview1.Items.Add ;
   item.Caption :='123324';
   item.SubItems.Add('32r5aefs');
   item.SubItems.Add('SGASD');
   item.SubItems.Add('3445645');
   end;
  end;
  
   上面的代码只是最基本的代码,仅可以通过键盘的上、下、左、右键控制EDIT在各个Column中切换,要将它做得更好,还要加入如拦截Column的宽度变化消息,以便Column变宽或变窄后相应的调整EDIT宽度等等。

转自:http://blog.tianya.cn/blogger/post_read.asp?BlogID=590356&PostID=38505324

posted @ 2013-03-23 15:24  stma  阅读(456)  评论(0)    收藏  举报