TListView
Метод 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 |
Страница 2 из 3