Метод GetItemAt позволяет получить координаты ListItem, по которой был клик, но только для первой колонки TListView. Если нужно узнать по какому элементу из другой колонки кликнул пользователь, то прийдётся объявить новый метод в наследованном классе:

 

Класс TEctoSoftTree представляет собой невизуальное дерево для манипулирования древоподобными структурами в памяти. Мной в очередной раз из любви к искусству

был изобретен велосипед :))), который тем не менее получился вполне съедобным и несмотря на наличие других вариантов решения задачи будет использоваться мной

хотя бы назло врагам :) Буду рад если еще кому-то он придется по вкусу. Просьба при внесении изменений и дополнений в код, а также обнаружении ошибок

(которых здесь нет ;) уведомить автора, т.е. меня

 

Малышев Владимир aka "мыш"

 

Code:

{

Question:

How do I capture a column resize event in TListView, the OnResize

only works when the ListView is changed?

 

Answer:

The event can be added with a bit of work. See the custom TListview derivative

below. It has 3 new events:

OnColumnResize, OnBeginColumnResize, OnEndColumnResize

}

 

unit PBExListview;

 

interface

 

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

Dialogs, ComCtrls;

 

type

TLVColumnResizeEvent = procedure(Sender: TCustomListview;

   columnindex: Integer;

   columnwidth: Integer) of object;

TPBExListview = class(TListview)

private

   FBeginColumnResizeEvent: TLVColumnResizeEvent;

   FEndColumnResizeEvent: TLVColumnResizeEvent;

   FColumnResizeEvent: TLVColumnResizeEvent;

 

protected

   procedure DoBeginColumnResize(columnindex, columnwidth: Integer);

     virtual;

   procedure DoEndColumnResize(columnindex, columnwidth: Integer);

     virtual;

   procedure DoColumnResize(columnindex, columnwidth: Integer);

     virtual;

   procedure WMNotify(var Msg: TWMNotify); message WM_NOTIFY;

   function FindColumnIndex(pHeader: pNMHdr): Integer;

   function FindColumnWidth(pHeader: pNMHdr): Integer;

   procedure CreateWnd; override;

published

   property OnBeginColumnResize: TLVColumnResizeEvent

     read FBeginColumnResizeEvent write FBeginColumnResizeEvent;

   property OnEndColumnResize: TLVColumnResizeEvent

     read FEndColumnResizeEvent write FEndColumnResizeEvent;

   property OnColumnResize: TLVColumnResizeEvent

     read FColumnResizeEvent write FColumnResizeEvent;

end;

 

procedure Register;

 

implementation

 

uses CommCtrl;

 

procedure Register;

begin

RegisterComponents('PBGoodies', [TPBExListview]);

end;

 

procedure TPBExListview.DoBeginColumnResize(columnindex, columnwidth: Integer);

begin

if Assigned(FBeginColumnResizeEvent) then

   FBeginColumnResizeEvent(Self, columnindex, columnwidth);

end;

 

procedure TPBExListview.DoEndColumnResize(columnindex, columnwidth: Integer);

begin

if Assigned(FEndColumnResizeEvent) then

   FEndColumnResizeEvent(Self, columnindex, columnwidth);

end;

 

procedure TPBExListview.DoColumnResize(columnindex, columnwidth: Integer);

begin

if Assigned(FColumnResizeEvent) then

   FColumnResizeEvent(Self, columnindex, columnwidth);

end;

 

function TPBExListview.FindColumnIndex(pHeader: pNMHdr): Integer;

var

hwndHeader: HWND;

iteminfo: THdItem;

ItemIndex: Integer;

buf: array [0..128] of Char;

begin

Result := -1;

hwndHeader := pHeader^.hwndFrom;

ItemIndex := pHDNotify(pHeader)^.Item;

FillChar(iteminfo, SizeOf(iteminfo), 0);

iteminfo.Mask := HDI_TEXT;

iteminfo.pszText := buf;

iteminfo.cchTextMax := SizeOf(buf) - 1;

Header_GetItem(hwndHeader, ItemIndex, iteminfo);

if CompareStr(Columns[ItemIndex].Caption, iteminfo.pszText) = 0 then

   Result := ItemIndex

else

begin

   for ItemIndex := 0 to Columns.Count - 1 do

     if CompareStr(Columns[ItemIndex].Caption, iteminfo.pszText) = 0 then

     begin

       Result := ItemIndex;

       Break;

     end;

end;

end;

 

procedure TPBExListview.WMNotify(var Msg: TWMNotify);

begin

inherited;

case Msg.NMHdr^.code of

   HDN_ENDTRACK:

     DoEndColumnResize(FindColumnIndex(Msg.NMHdr),

       FindColumnWidth(Msg.NMHdr));

   HDN_BEGINTRACK:

     DoBeginColumnResize(FindColumnIndex(Msg.NMHdr),

       FindColumnWidth(Msg.NMHdr));

   HDN_TRACK:

     DoColumnResize(FindColumnIndex(Msg.NMHdr),

       FindColumnWidth(Msg.NMHdr));

end;

end;

 

procedure TPBExListview.CreateWnd;

var

wnd: HWND;

begin

inherited;

wnd := GetWindow(Handle, GW_CHILD);

SetWindowLong(wnd, GWL_STYLE,

   GetWindowLong(wnd, GWL_STYLE) and not HDS_FULLDRAG);

end;

 

function TPBExListview.FindColumnWidth(pHeader: pNMHdr): Integer;

begin

Result := -1;

if Assigned(PHDNotify(pHeader)^.pItem) and

   ((PHDNotify(pHeader)^.pItem^.mask and HDI_WIDTH) <> 0) then

   Result := PHDNotify(pHeader)^.pItem^.cxy;

end;

 

end.

 

 

 

Сегодня я хочу рассказать, как можно заменить некоторые элементы в стандартный TListView.

Например, у вас есть 5 пунктов и хотите поменять местами первый и третий элементы

 

Проблема, что стандартный компонент TListView не такой способ и вы должны понимать это сами.

 

Мы помним, что стандартный путь от старого Паскаля раза (для чисел):

 

Code:

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

  StdCtrls, ComCtrls;

 

type

  TMain = class(TForm)

    ListView1: TListView;

    Button1: TButton;

    Button2: TButton;

    procedure FormCreate(Sender : TObject);

    procedure FormDestroy(Sender : TObject);

    procedure Button1Click(Sender : TObject);

    procedure Button2Click(Sender : TObject);

  private

    ListViewRadioList: TList;

    procedure ListViewRadioCreate(List : TListView; R : TRect);

    procedure ListViewRadioClear(List : TListView; Liste : TList);

    procedure ListViewRadioFree(List : TListView; Liste : TList);

    procedure ListViewListSelected(Item : integer; List : TListView);

    procedure ListViewRadioClick(Sender : TObject);

  public

    { Public-Deklarationen }

  end;

 

var

  Main : TMain;

 

implementation

 

{$R *.DFM}

 

procedure TMain.FormCreate(Sender : TObject);

begin

  ListViewRadioList := TList.Create;

end;

 

procedure TMain.FormDestroy(Sender : TObject);

begin

  ListViewRadioFree(ListView1, ListViewRadioList);

end;

 

procedure TMain.Button1Click(Sender : TObject);

var

  R : TRect;

  NewColumn : TListColumn;

  ListItem : TListItem;

  I : integer;

begin

  with ListView1 do

  begin

    ViewStyle := vsReport;

    Align := alLeft;

    RowSelect := True;

    ReadOnly := True;

    ShowColumnHeaders := False;

    NewColumn := Columns.Add;

    NewColumn.Width := 15;

    NewColumn := Columns.Add;

    NewColumn.Width := Width - 15 - 19; // - breite Button - breite vom Scrollbalken

   Items.BeginUpdate;

 

    for I := 0 to 9 do

    begin

      ListItem := Items.Add;

      R := Items[I].DisplayRect(drBounds);

      R.Left := 1;

      R.Right := Columns[0].Width;

      ListViewRadioCreate(ListView1, R);

      Items[I].Data := TRadioButton(ListViewRadioList[I]);

      ListItem.SubItems.Add('Test' + IntToStr(I));

    end;

    Items.EndUpdate;

  end;

end;

 

procedure TMain.Button2Click(Sender : TObject);

begin

  ListViewRadioClear(ListView1, ListViewRadioList);

end;

//------------------------------------------------------------------------------

 

procedure TMain.ListViewRadioCreate(List : TListView; R : TRect);

  function NewViewRadio: TRadioButton;

  begin

    Result := TRadioButton.Create(Self);

    Result.Parent := List;

    Result.BoundsRect := R;

    Result.OnClick := ListViewRadioClick;

  end;

begin

  ListViewRadioList.Add(NewViewRadio);

end;

//------------------------------------------------------------------------------

 

procedure TMain.ListViewRadioFree(List : TListView; Liste : TList);

var

  I : integer;

begin

  if Liste.Count - 1 < 0 then exit;

  for I := 0 to Liste.Count - 1 do TRadioButton(Liste[I]).Free;

  Liste.Free;

end;

//------------------------------------------------------------------------------

 

procedure TMain.ListViewRadioClear(List : TListView; Liste : TList);

var

  I : integer;

begin

  if Liste.Count - 1 < 0 then exit;

  List.Items.BeginUpdate;

  for I := 0 to Liste.Count - 1 do TRadioButton(Liste[I]).Free;

  List.Items.Clear;

  Liste.Clear;

  List.Items.EndUpdate;

end;

//------------------------------------------------------------------------------

 

procedure TMain.ListViewListSelected(Item : integer; List : TListView);

begin

  with List do

  begin

    try

      SetFocus;

    except

    end;

    Selected := Items[Item];

    ItemFocused := Selected;

  end;

end;

 

//------------------------------------------------------------------------------

procedure TMain.ListViewRadioClick(Sender : TObject);

var

  I : integer;

begin

  for I := 0 to ListViewRadioList.Count - 1 do

    if TRadioButton(ListViewRadioList[I]).Checked then

    begin

      ListViewListSelected(I, ListView1);

      break;

    end;

end;

 

end.

 

Code:

procedure TForm1.ListView1MouseUp(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

var

  Item: TListItem;

  HitTest: THitTests;

begin

  // Welchem Item gehцrt die CheckBox

// Which item belongs to the checkbox

Item := ListView1.GetItemAt(x, y);

 

  // Was wurde vom Item genau angeklickt

// What kind of thing was hit on the item

HitTest := ListView1.GetHitTestInfoAt(x, y);

 

  // Falls ein Item angeklickt wurde und davon die Checkbox

// If an Item was hit and exactly his checkbox

if (Item <> nil) and (HitTest = [htOnStateIcon]) then

  begin

    ////////////////////////////////

   // Hier das OnCheck behandeln //

   // Handle OnCheck here        //

   ////////////////////////////////

   // Beispiel

   // Example

   //

   //  if Item.Checked = False then

   //  begin

   //    if (Item.Index = 0) or (ListView1.Items.Item[Item.Index - 1].Checked = True) then

   //      Item.Checked := True else Item.Checked := False;

   //  end else

   //    begin

   //    if (Item.Index = ListView1.Items.Count - 1) or (ListView1.Items.Item[Item.Index + 1].Checked = False) then Item.Checked := False else

   //      Item.Checked := True;

   //  end;

end;

end;

 

 

 The following example shows how to show all files and their  associated icons of a folder in a TListView.

To test the code, you need a ListView1 and a ImageList1 where the icons are stored.

 

Code:

// declarations from commctrl.h

type

  TLVGROUP = record

    cbSize: UINT;

    mask: UINT;

    pszHeader: LPWSTR;

    cchHeader: Integer;

    pszFooter: LPWSTR;

    cchFooter: Integer;

    iGroupIdL: Integer;

    stateMask: UINT;

    state: UINT;

    uAlign: UINT;

  end;

 

  tagLVITEMA = packed record

    mask: UINT;

    iItem: Integer;

    iSubItem: Integer;

    state: UINT;

    stateMask: UINT;

    pszText: PAnsiChar;

    cchTextMax: Integer;

    iImage: Integer;

    lParam: lParam;

    iIndent: Integer;

    iGroupId: Integer;

    cColumns: UINT;

    puColumns: PUINT;

  end;

  TLVITEMA = tagLVITEMA;

 

const

  LVM_ENABLEGROUPVIEW = LVM_FIRST + 157;

  LVM_MOVEITEMTOGROUP = LVM_FIRST + 154;

  LVM_INSERTGROUP     = LVM_FIRST + 145;

 

  LVIF_GROUPID = $0100;

 

  LVGF_HEADER  = $00000001;

  LVGF_ALIGN   = $00000008;

  LVGF_GROUPID = $00000010;

 

  LVGA_HEADER_LEFT   = $00000001;

  LVGA_HEADER_CENTER = $00000002;

  LVGA_HEADER_RIGHT  = $00000004;

 

 

procedure TForm1.Button1Click(Sender: TObject);

var

  LvGroup: TLVGROUP;

  LvItemA: TLVITEMA;

  ListItem: TListItem;

  I: Byte;

begin

  // Fill listview with random data

Randomize;

  for i := 1 to 10 do

  begin

    ListItem := ListView1.Items.Add;

    ListItem.Caption := IntToStr(Random(100));

  end;

 

  SendMessage(ListView1.Handle, LVM_ENABLEGROUPVIEW, 1, 0);

 

  // Create Group1

FillChar(LvGroup, SizeOf(TLVGROUP), 0);

  with LvGroup do

  begin

    cbSize := SizeOf(TLVGROUP);

    mask := LVGF_HEADER or LVGF_ALIGN or LVGF_GROUPID;

    pszHeader := 'Group 1';

    cchHeader := Length(LvGroup.pszHeader);

    iGroupIdL := 0;

    uAlign := LVGA_HEADER_CENTER;

  end;

  SendMessage(ListView1.Handle, LVM_INSERTGROUP, 0, Longint(@LvGroup));

 

  // Create Group2

FillChar(LvGroup, SizeOf(LvGroup), 0);

  with LvGroup do

  begin

    cbSize := SizeOf(TLVGROUP);

    mask := LVGF_HEADER or LVGF_ALIGN or LVGF_GROUPID;

    pszHeader := 'Group 2';

    cchHeader := Length(LvGroup.pszHeader);

    iGroupIdL := 1;

    uAlign := LVGA_HEADER_LEFT

  end;

  SendMessage(ListView1.Handle, LVM_INSERTGROUP, 1, Longint(@LvGroup));

 

  // Assign items to the groups

for I := 0 to ListView1.Items.Count - 1 do

  begin

    with LvItemA do

    begin

      FillChar(LvItemA, SizeOf(TLvItemA), 0);

      mask := LVIF_GROUPID;

      iItem := I;

      iGroupId := Random(2);

    end;

    SendMessage(ListView1.Handle, LVM_SETITEM, 0, Longint(@LvItemA))

  end;

end;

 

 

 

// XPManifest needed!

 

 

Code:

procedure TForm1.Button1Click(Sender: TObject);

var

  i: integer;

begin

  with Listview1 do

    // MultiSelect := True;

   // ViewStyle := vsReport;

   for i := 0 to Items.Count - 1 do

      if Items[i].Selected then

        Items[i].Caption := Items[i].Caption + ' - Selected!';

end;

 

Code:

// Move item 1 after item 4

 

function MoveListViewItem(listView: TListView; ItemFrom, ItemTo: Word): Boolean;

var

  Source, Target: TListItem;

begin

  Result := False;

  listview.Items.BeginUpdate;

  try

    Source := listview.Items[ItemFrom];

    Target := listview.Items.Insert(ItemTo);

    Target.Assign(Source);

    Source.Free;

    Result := True;

  finally

    listview.Items.EndUpdate;

  end;

end;

 

procedure TForm1.Button1Click(Sender: TObject);

begin

  // Listview1.ViewStyle := vsReport;

if MoveListViewItem(Listview1, 1, 4) then

    ShowMessage('Moved!');

end;

Code:

Label1.Caption := ShellListView1.Folders[ShellListView1.ItemIndex].PathName

 

{**************************************************************}

 

{

To retrieve full paths to each file selected files:

}

 

var

  path: string;

begin

  for i:=0 to ShellListView1.SelCount-1 do

  begin

    path := ShellListView1.Folders[ShellListView1.GetNextItem(ShellListView1.Selected,

              sdAll,[isSelected]).Index+i-1].PathName;

    // ...

end;

end