Автор: Rustam Kafarov

 

При использовании компонента TTreeView возникают проблемы при собственной отрисовке содержимого компонента в событиях OnCustomDraw, OnCustomDrawItem, OnAdvancedCustomDraw, OnAdvancedCustomDrawItem. Проблема проявляется когда свойства Canvas компонента устанавливаются вторично. К примеру, при попытке изменить цвет фонта во второй раз, соотвествующих изменений НЕ ПОСЛЕДУЕТ. Тоже самое и со свойствами Brush, Pen.

 

Проверено на Дельфи 5.

 

Контрольный пример (на форме TTreeView и TCheckBox):

 

 

Code:

procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;

Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);

begin

if cdsSelected in State then

   Sender.Canvas.Font.Style := Sender.Canvas.Font.Style + [fsUnderline];

end;

 

 

Code:

uses

CommCtrl;

 

procedure SetNodeBoldState(Node: TTreeNode; Value: Boolean);

var

TVItem: TTVItem;

begin

if not Assigned(Node) then Exit;

with TVItem do

begin

   mask := TVIF_STATE or TVIF_HANDLE;

   hItem := Node.ItemId;

   stateMask := TVIS_BOLD;

   if Value then state := TVIS_BOLD 

   else

     state := 0;

   TreeView_SetItem(Node.Handle, TVItem);

end;

end;

 

// Example: Make the first node bold.

// Beispiel: Erster Eintrag fett machen.

 

procedure TForm1.Button1Click(Sender: TObject);

begin

SetNodeBoldState(TreeView1.Items[0], True);

end;

 

 

Автор: Васильев Василий

Code:

unit Unit1;

 

interface

 

uses

Windows, Messages, SysUtils, Variants, Classes, Controls, Forms,

Dialogs, StdCtrls, ComCtrls;

 

type

TForm1 = class(TForm)

   TreeView1: TTreeView;

   Label1: TLabel;

   procedure TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);

   procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;

     State: TDragState; var Accept: Boolean);

private

   { Private declarations }

   procedure MoveNode(TargetNode, SourceNode: TTreeNode);

public

   { Public declarations }

end;

 

var

Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

//

// Procedure which will move node and its subnodes

//

 

procedure TForm1.MoveNode(TargetNode, SourceNode: TTreeNode);

var

nodeTmp: TTreeNode;

i: Integer;

begin

with TreeView1 do

begin

   nodeTmp := Items.AddChild(TargetNode, SourceNode.Text);

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

   begin

     MoveNode(nodeTmp, SourceNode.Item[i]);

   end;

end;

end;

 

procedure TForm1.TreeView1DragDrop(Sender, Source: TObject; X, Y: Integer);

var

TargetNode, SourceNode: TTreeNode;

begin

with TreeView1 do

begin

   TargetNode := GetNodeAt(X, Y); // Get target node

   SourceNode := Selected;

   if (TargetNode = nil) then

   begin

     EndDrag(False);

     Exit;

   end;

   MoveNode(TargetNode, SourceNode);

   SourceNode.Free;

end;

end;

 

procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

begin

if (Sender = TreeView1) then // If TRUE than accept the draged item

begin

   Accept := True;

end;

end;

 

end.

 

Code:

procedure TForm1.TreeView1ContextPopup(Sender: TObject; MousePos: TPoint;

  var Handled: Boolean);

var

  tmpNode: TTreeNode;

begin

  tmpNode := (Sender as TTreeView).GetNodeAt(MousePos.X, MousePos.Y);

  if tmpNode <> nil then

    TTreeView(Sender).Selected := tmpNode;

end;

 

На форме стоит TreeView, PageControl и кнопка.

При смене страницы - меняется текущий узел, а при смене узла меняется страница.

Code:

procedure LoadIniToTree(const FName: string; Tree: TTreeView);

var LS, LV: TStrings;

   i, j: integer;

   root: TTreeNode;

   n: string;

   p: PString;

begin

    Tree.Items.Clear;  // очищаем дерево

    with TIniFile.Create(FName) do // пытаемся открыть файл FName

    try

      LS := TStringList.Create;  // список названий секций

      try

        ReadSections(LS);          // читаем все секции в список

        LV := TStringList.Create;   // список пар "имя=значение"

        try

          for i := 0 to LS.Count-1 do   // для всех секций...

          begin

            LV.Clear;                   // подготовим список

            ReadSectionValues(LS[i], LV);  // читаем список пар "имя=значение" для текущей секции

            root := Tree.Items.Add(nil, LS[i]); // добавляем корневой узел (имя текущей секции)

            for j := 0 to LV.Count-1 do    // для всех пар "имя=значение"...

            begin

             n := LV.Names[j];  // выделяем "имя"

 

             // добавляем дочерний по отношению к root узел,

             // в качестве текста исп. "имя"

             // в качестве значения поля Data = "значение"

             New(p);

             p^ := LV.Values[n];

             Tree.Items.AddChildObject(root, n, p);

            end;

          end;

        finally

          LV.Free;

        end;

      finally

        LS.Free;

      end;

    finally

      Free;  // корректно уничтожаем объект TIniFile

    end;

end;

 

// Применение:

 

procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);

begin

    if (TreeView1.Selected <> nil) and (TreeView1.Selected.Parent <> nil) then

    begin

       Edit1.Text := TreeView1.Selected.Text;

       Edit2.Text := String(TreeView1.Selected.Data^);

    end else

    begin

      Edit1.Text := '';

      Edit2.Text := '';

    end;

end;

 

// После использования не забыть освободить память, напр. так:

 

procedure TForm1.TreeView1Deletion(Sender: TObject; Node: TTreeNode);

begin

if Node.Data <> nil then

   Dispose(PString(Node.Data));

end;

 

Code:

{

If you have installed the Internet Explorer 4.0 or high, in TTreeView component

always displaying a hint for cutted items. It's useful but sometimes prevents and

irritates (at least, me). But there is a simple way to switch off this feature:

}

 

procedure TForm1.FormShow(Sender: TObject);

const

  TVS_NOTOOLTIPS = $0080;

begin

  SetWindowLong(Treeview1.Handle, GWL_STYLE,

    GetWindowLong(TreeView1.Handle, GWL_STYLE) xor TVS_NOTOOLTIPS);

end;

 

 

Автор: Eugene Mayevski

 

TCustomTreeView.WMNotify. О том, что такое тип notify'а TTM_NEEDTEXT пpочтешь в хелпе. Убpать хинты можно, пеpекpыв обpаботчик для этого уведомительного сообщения.

 

Code:

var

  SL : TStringList;

 

procedure TForm1.CutBtnClick(Sender: TObject);

var

  i, j, StartLevel : integer;

  TNSel : TTreeNode;

begin

  TNSel := TreeView1.Selected;

  if TNSel <> nil then begin

    StartLevel := TNSel.Level;

    i := TNSel.AbsoluteIndex;

    j := i; // note for later deletion

    if SL = nil then

      SL := TStringList.Create

    else

      SL.Clear;

    SL.AddObject(TNSel.Text, pointer(0));

    inc(i);

    with TreeView1 do begin

      while Items[i].Level > StartLevel do begin

        {stop before next sibling to top node\}

        SL.AddObject(Items[i].Text, pointer(Items[i].Level - StartLevel));

        inc(i);

      end; {while Items[i].Level > StartLevel\}

      Items[j].Delete;

    end; {with TreeView1\}

  end; {if TNSel <> nil\}

end;

 

procedure TForm1.PasteBtnClick(Sender: TObject);

var

  i, Level : integer;

  TNSel, TN : TTreeNode;

begin

  with TreeView1 do begin

    TNSel := Selected;

    if TNSel <> nil then begin

      TN := Items.Insert(TNSel, SL.Strings[0]);

      Level := integer(SL.Objects[0]); // should be 0

      for i := 1 to SL.Count - 1 do begin

        if integer(SL.Objects[i]) < Level then begin

          {go up one level\}

          TN := TN.Parent;

          Level := integer(SL.Objects[i]);

        end; {if integer(SL.Objects[i]) < Level\}

        if Level = integer(SL.Objects[i]) then

          {same level\}

          TN := Items.Add(TN, SL.Strings[i])

        else begin

          {go down one level\}

          TN := Items.AddChild(TN, SL.Strings[i]);

          Level := integer(SL.Objects[i]);

        end; {if Level = integer(SL.Objects[i])\}

      end; {for i := 1 to SL.Count - 1\}

    end; {if TNSel <> nil\}

  end; {with TreeView1\}

end;

 

 

Code:

var

  SL : TStringList;

 

procedure TForm1.CutBtnClick(Sender: TObject);

var

  i, j, StartLevel : integer;

  TNSel : TTreeNode;

begin

  TNSel := TreeView1.Selected;

  if TNSel <> nil then begin

    StartLevel := TNSel.Level;

    i := TNSel.AbsoluteIndex;

    j := i; // note for later deletion

    if SL = nil then

      SL := TStringList.Create

    else

      SL.Clear;

    SL.AddObject(TNSel.Text, pointer(0));

    inc(i);

    with TreeView1 do begin

      while Items[i].Level > StartLevel do begin

        {stop before next sibling to top node\}

        SL.AddObject(Items[i].Text, pointer(Items[i].Level - StartLevel));

        inc(i);

      end; {while Items[i].Level > StartLevel\}

      Items[j].Delete;

    end; {with TreeView1\}

  end; {if TNSel <> nil\}

end;

 

procedure TForm1.PasteBtnClick(Sender: TObject);

var

  i, Level : integer;

  TNSel, TN : TTreeNode;

begin

  with TreeView1 do begin

    TNSel := Selected;

    if TNSel <> nil then begin

      TN := Items.Insert(TNSel, SL.Strings[0]);

      Level := integer(SL.Objects[0]); // should be 0

      for i := 1 to SL.Count - 1 do begin

        if integer(SL.Objects[i]) < Level then begin

          {go up one level\}

          TN := TN.Parent;

          Level := integer(SL.Objects[i]);

        end; {if integer(SL.Objects[i]) < Level\}

        if Level = integer(SL.Objects[i]) then

          {same level\}

          TN := Items.Add(TN, SL.Strings[i])

        else begin

          {go down one level\}

          TN := Items.AddChild(TN, SL.Strings[i]);

          Level := integer(SL.Objects[i]);

        end; {if Level = integer(SL.Objects[i])\}

      end; {for i := 1 to SL.Count - 1\}

    end; {if TNSel <> nil\}

  end; {with TreeView1\}

end;