Приложение MiniRegistry
Рисунок 5.6. Приложение Mini-Registry browser А вот и весь его исходный код:
Листинг 5.1. Приложение Mini-Registry-browser, главный модуль
unit main;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Grids, Outline, ComCtrls, ImgList, ExtCtrls;
type
TForml = class(TForm)
TreeViewl: TTreeView;
ListViewl: TListView;
ImageListl: TImageList;
Splitterl: TSplitter;
procedure FormCreate(Sender: TObject);
procedure TreeViewlChange(Sender: TObject; Node: TTreeNode);
procedure FormDestroy(Sender: TObject);
procedure TreeViewlExpanded(Sender: TObject; Node: TTreeNode);
procedure TreeViewlGetlmagelndex(Sender: TObject; Node: TTreeNode);
private
{ Private declarations }
public
{ Public declarations }
procedure ShowSubKeys(ParentNode: TTreeNode;depth: Integer);
function GetFullNodeName(Node: TTreeNode):string;
end;
var
Forml: TForml;
implementation
uses registry;
{$R *.DFM}
var reg : TRegistry;
procedure TForml.FormCreate(Sender: TObject);
var root : TTreeNode;
begin
Reg := TRegistry.Create;
ListViewl.ViewStyle := vsReport;
with ListViewl do
begin
with Columns.Add do
begin
Width := ListViewl.Width div 3-2;
Caption := 'Name';
end;
with Columns.Add do
begin
Width := ListViewl.Width div 3*2-2;
Caption := 'Value';
end;
end;
TreeViewl.Items.Clear;
Reg.RootKey := HKEY_LOCAL_MACHINE;
Root := TreeViewl.Items.Add(nil,'HKEY_LOCAL_MACHINE');
TreeViewl.Items.AddChildtroot,'');
end;
procedure TForml.FormDestroy(Sender: TObject);
begin
Reg.Free;
end;
function TForml.GetFullNodeName(Node: TTreeNode):string;
var CurNode : TTreeNode;
begin
Result:=''; CurNode := Node;
while CurNode.Parentonil do
begin
Result:= '\'+CurNode.Text + Result;
CurNode := CurNode.Parent;
end;
end;
procedure TForml.TreeViewlChange(Sender: TObject; Node: TTreeNode);
var s: string;
Keylnfo : TRegKeylnfo;
ValueNames : TStringList;
i : Integer;
DataType : TRegDataType;
begin
ListViewl.Items.Clear;
s:= GetFullNodeName(Node);
if not Reg.OpenKeyReadOnly(s) then Exit;
Reg.GetKeylnfo(Keylnfo);
if Keylnfo.NumValues<=0 then Exit;
ValueNames := TStringList.Create;
Reg.GetValueNames(ValueNames);
for i := 0 to ValueNames.Count-1 do
with ListViewl.Items.Add do
begin
Caption := ValueNames[i];
DataType := Reg.GetDataType(ValueNames[i]);
Case DataType of
rdString: s := Reg.ReadString(ValueNames[i]);
rdlnteger: s:= '0x'+IntToHex(Reg.Readlnteger(ValueNames[i]),8);
rdBinary: s:='Binary';
else s:= '???';
end;
Subltems.Add(s);
Imagelndex :=1;
end;
ValueNames.Free;
end;
procedure TForml.ShowSubKeys(ParentNode: TTreeNode;depth: Integer);
var ParentKey: string;
KeyNames : TStringList;
KeyInfo : TRegKeylnfo;
CurNode : TTreeNode; i : Integer;
begin
Cursor := crHourglass;
TreeViewl.Items.BeginUpdate;
ParentKey := GetFullNodeName(ParentNode);
if ParentKeyO1' then
Reg.OpenKeyReadOnly(ParentKey)
else
Reg.OpenKeyReadOnly('\') ;
Reg.GetKeylnfo(Keylnfo) ;
if KeyInfo.NumSubKeys<=0 then Exit;
KeyNames := TStringList.Create;
Reg.GetKeyNames(KeyNames);
While ParentNode.GetFirstChildonil do ParentNode.GetFirstChild.Delete;
if (KeyNames.Count>0) then for i:=0 to KeyNames.Count-1 do
begin
Reg.OpenKeyReadOnly(ParentKey+'\'-t-KeyNames[ i ]) ;
Reg.GetKeylnfo(Keylnfo);
CurNode := TreeViewl.Items.AddChild(ParentNode,KeyNames[i];
if KeyInfo.NumSubKeys>0 then
begin
TreeViewl.Items.AddChild(CurNode, '');
end;
end;
KeyNames.Free;
TreeViewl.Items.EndUpdate;
Cursor := crDefault;
end;
procedure TForml.TreeViewlExpanded(Sender: TObject; Node: TTreeNode);
begin
ShowSubKeys(Node,1);
end;
procedure TForml.TreeViewlGetlmagelndex(Sender: TObject; Node: TTreeNode);
begin
with Node do
begin
if Expanded then Imagelndex := 2
else Imagelndex := 3;
end;
end;
end.
Для работы с системным реестром используется объект VCL TRegistry, удачно инкапсулирующий все предназначенные для этого функции Windows API. В обработчике события OnCreate главной формы создается объект Reg, а также к списку Listview1 добавляются два заголовка (свойство Columns).
Пояснений требует принцип построения дерева ключей. Во-первых, это приложение отображает только один из системных ключей (а именно HKEY_LOCAL_MACHINE); при желании его можно заменить или добавить остальные. Во-вторых, попытка построить все "развесистое" дерево ключей сразу займет слишком много времени и наверняка не понравится пользователям. Вспомним, ведь утилита Registry Editor работает довольно быстро. Значит, придется строить дерево динамически — создавать и показывать дочерние узлы в момент развертывания родительского узла. Для этого используется событие OnExpand компонента TreeView1.
Остановимся на секунду. А какие узлы помечать кнопкой разворачивания (с пометкой "+"), ведь у родительского узла еще нет потомков? Выход из положения такой — в момент построения ключа проверить, есть ли у него дочерние. Если да, то к нему добавляется один (фиктивный) пустой ключ. Его единственная роль — дать системе поставить "+" против родительского узла.
Когда же пользователь щелкнул на кнопке, отмеченной знаком "+", и родительский узел разворачивается, фиктивный дочерний узел удаляется и вместо него создаются узлы настоящие, полученные путем сканирования реестра (см. метод ShowSubKeys).
Снабдим узлы картинками. Для этого в компонент imageList1 поместим картинки, соответствующие открытой и закрытой папкам. Напомним, что для отрисовки и смены картинок есть специальные события — OnGetlmageIndex И OnGetSelectedIndex. В данном примере у двух ЭТИХ событий один обработчик: развернутому узлу он сопоставляет картинку раскрытой папки, а свернутому — закрытой.
В заключение нужно сказать об очень важной особенности компонента TListview. Когда он отображает большой объем информации, обработка данных может затянуться очень и очень надолго и занять слишком много памяти. Выход — перевести список в так называемый виртуальный режим. Он применяется для тех случаев, когда элементов в списке слишком много и хранить их там невозможно из соображений экономии времени или памяти. Выход из положения прост:
1. Переводим компонент в виртуальный режим установкой свойства OwnerData в значение True.
2. Сообщаем списку сколько в нем должно быть элементов установкой нужного значения items.Count.
3. Чтобы предоставить нужные данные, программист должен предусмотреть обработку событий OnData, OnDataFind, OnDataHint и OnDataStateChange. Как минимум нужно описать обработчик события OnData.
TLVOwnerDataEvent = procedure(Sender: TCbject; Item: TListltem) of object;
Вам передается объект TListitem, и внутри обработчика события OnData необходимо динамически "оформить" его — полностью, от заголовка до картинок.
Возникает это событие перед каждой перерисовкой списка. Так что, если сбор данных для вашего списка занимает более или менее продолжительное время, лучше не связывать его с событием OnData — перерисовка сильно затянется. К тому же в виртуальном режиме сортировать список невозможно.
Borland прилагает к Delphi 7 прекрасный пример к вышесказанному — Virtual Listview. К нему и отсылаем заинтересованного читателя.
Примечание
Примечание
Ответы на вопросы по компоненту TListview можно найти сразу в двух местах: "родном" файле справки d7vcl.hlp и файле справки Windows Win32.hip. Во втором из них информация содержится в виде описания сообщений, посылаемых окну класса Listview, и соответствующих им макросов. Некоторые из них позволят вам расширить функциональные возможности компонента TListview. Эти макросы содержатся в файле CommCtrl.pas.