home *** CD-ROM | disk | FTP | other *** search
/ PC World Plus! (NZ) 2001 June / HDC50.iso / Runimage / Delphi50 / Demos / CustomDraw / customdrawtreeview.pas < prev   
Pascal/Delphi Source File  |  1999-08-11  |  12KB  |  400 lines

  1. unit CustomDrawTreeView;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   ComCtrls, ExtDlgs, StdCtrls, ExtCtrls, ColorGrd, ImgList, Menus;
  8.  
  9. type
  10.   TCustomDrawForm = class(TForm)
  11.     TV: TTreeView;
  12.     ImageList: TImageList;
  13.     MainMenu1: TMainMenu;
  14.     Drawing1: TMenuItem;
  15.     Font1: TMenuItem;
  16.     Background1: TMenuItem;
  17.     Color1: TMenuItem;
  18.     Bitmap1: TMenuItem;
  19.     DefaultDrawing1: TMenuItem;
  20.     OnCustomDraw1: TMenuItem;
  21.     OnCustomDrawItem1: TMenuItem;
  22.     BrushStyle1: TMenuItem;
  23.     Solid1: TMenuItem;
  24.     Clear1: TMenuItem;
  25.     Horizontal1: TMenuItem;
  26.     Vertical1: TMenuItem;
  27.     FDiagonal1: TMenuItem;
  28.     BDiagonal1: TMenuItem;
  29.     Cross1: TMenuItem;
  30.     DiagCross1: TMenuItem;
  31.     File1: TMenuItem;
  32.     Exit1: TMenuItem;
  33.     N2: TMenuItem;
  34.     TVFontDialog: TFontDialog;
  35.     Tile1: TMenuItem;
  36.     Stretch1: TMenuItem;
  37.     None1: TMenuItem;
  38.     Selection1: TMenuItem;
  39.     SelectedFontDialog: TFontDialog;
  40.     BkgColorDialog: TColorDialog;
  41.     SelBkgColorDialog: TColorDialog;
  42.     SelectionBackground1: TMenuItem;
  43.     ButtonColor1: TMenuItem;
  44.     ButtonSize1: TMenuItem;
  45.     ButtonColorDialog: TColorDialog;
  46.     Image1: TImage;
  47.     TreeView1: TMenuItem;
  48.     Color2: TMenuItem;
  49.     TVColorDialog: TColorDialog;
  50.     CustomDraw1: TMenuItem;
  51.     Font2: TMenuItem;
  52.     procedure FormCreate(Sender: TObject);
  53.     procedure TVCustomDraw(Sender: TCustomTreeView; const ARect: TRect;
  54.       var DefaultDraw: Boolean);
  55.     procedure TVCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  56.       State: TCustomDrawState; var DefaultDraw: Boolean);
  57.     procedure TVGetImageIndex(Sender: TObject; Node: TTreeNode);
  58.     procedure TVGetSelectedIndex(Sender: TObject; Node: TTreeNode);
  59.     procedure Exit1Click(Sender: TObject);
  60.     procedure Selection1Click(Sender: TObject);
  61.     procedure Color1Click(Sender: TObject);
  62.     procedure SelectionBackground1Click(Sender: TObject);
  63.     procedure Solid1Click(Sender: TObject);
  64.     procedure None1Click(Sender: TObject);
  65.     procedure OnCustomDraw1Click(Sender: TObject);
  66.     procedure OnCustomDrawItem1Click(Sender: TObject);
  67.     procedure TVExpanded(Sender: TObject; Node: TTreeNode);
  68.     procedure ButtonColor1Click(Sender: TObject);
  69.     procedure ButtonSize1Click(Sender: TObject);
  70.     procedure Drawing1Click(Sender: TObject);
  71.     procedure Color2Click(Sender: TObject);
  72.     procedure CustomDraw1Click(Sender: TObject);
  73.     procedure Font2Click(Sender: TObject);
  74.   private
  75.     FButtonSize: Integer;
  76.     FDefaultDraw,
  77.     FDefaultDrawItem: Boolean;
  78.     FBackgroundColor: TColor;
  79.     FBrushStyle: TBrushStyle;
  80.     procedure DrawButton(ARect: TRect; Node: TTreeNode);
  81.     procedure DrawImage(NodeRect: TRect; ImageIndex: Integer);
  82.     procedure SetCustomDraw(Value: Boolean);
  83.     { Private declarations }
  84.   public
  85.     { Public declarations }
  86.   end;
  87.  
  88. var
  89.   CustomDrawForm: TCustomDrawForm;
  90.  
  91. implementation
  92.  
  93. {$R *.DFM}
  94.  
  95. procedure TCustomDrawForm.FormCreate(Sender: TObject);
  96. begin
  97.   FBackgroundColor := clWindow;
  98.   FDefaultDraw := True;
  99.   FDefaultDrawItem := True;
  100.   FBrushStyle := bsSolid;
  101.   FButtonSize := 5;
  102.   BkgColorDialog.Color := clWindow;
  103.   SelBkgColorDialog.Color := clHighlight;
  104.   TVFontDialog.Font.Assign(TV.Font);
  105.   SelectedFontDialog.Font.Assign(TV.Font);
  106.   SelectedFontDialog.Font.Color := clHighlightText;
  107.   SelBkgColorDialog.Color := clHighlight;
  108.   TVColorDialog.Color := TV.Color;
  109. end;
  110.  
  111. procedure TCustomDrawForm.TVCustomDraw(Sender: TCustomTreeView; const ARect: TRect;
  112.   var DefaultDraw: Boolean);
  113. begin
  114. //This event should be used to draw any background colors or images.
  115. //ARect represents the entire client area of the TreeView.
  116. //Use the TreeView's canvas to do the drawing.
  117. //Note that drawing a background bitmap is not really supported by CustomDraw,
  118. //so scrolling can get messy. Best to subclass the TreeView and handle scrolling
  119. //messages.
  120.   with TV.Canvas do
  121.   begin
  122.     if None1.Checked then //no picture
  123.     begin
  124.       Brush.Color := BkgColorDialog.Color;
  125.       Brush.Style := FBrushStyle;
  126.       FillRect(ARect);
  127.     end else
  128.       if Tile1.Checked then //tile bitmap
  129.       begin
  130.         Brush.Bitmap := Image1.Picture.Bitmap;
  131.           FillRect(ARect);
  132.         end else //Stretch across the canvas.
  133.             StretchDraw(ARect, Image1.Picture.Bitmap);
  134.   end;
  135.   DefaultDraw := FDefaultDraw;
  136.   //setting DefaultDraw to false here prevents all calls to OnCustomDrawItem.
  137. end;
  138.  
  139. procedure TCustomDrawForm.DrawButton(ARect: TRect; Node: TTreeNode);
  140. var
  141.   cx, cy: Integer;
  142. begin
  143.   cx := ARect.Left + TV.Indent div 2;
  144.   cy := ARect.Top + (ARect.Bottom - ARect.Top) div 2;
  145.   with TV.Canvas do
  146.   begin
  147.     Pen.Color := ButtonColorDialog.Color;
  148.     //draw horizontal line.
  149.     if Node.HasChildren then
  150.     begin
  151.       PenPos := Point(cx+FButtonSize, cy);
  152.       LineTo(ARect.Left + TV.Indent + FButtonSize, cy);
  153.     end else
  154.     begin
  155.       PenPos := Point(cx, cy);
  156.       LineTo(ARect.Left + TV.Indent + FButtonSize, cy);
  157.     end;
  158.  
  159.     //draw half vertical line, top portion.
  160.     PenPos := Point(cx, cy);
  161.     LineTo(cx, ARect.Top-1);
  162.  
  163.     if ((Node.GetNextVisible <> nil) and (Node.GetNextVisible.Level = Node.Level))
  164.     or (Node.GetNextSibling <> nil) then
  165.     //draw bottom portion of half vertical line.
  166.     begin
  167.       PenPos := Point(cx, cy);
  168.       LineTo(cx, ARect.Bottom+1);
  169.     end;  
  170.  
  171.     if Node.HasChildren then
  172.     begin
  173.       //Let's try a circular button instead
  174.       Ellipse(cx-FButtonSize, cy-FButtonSize, cx+FButtonSize, cy+FButtonSize);
  175.  
  176.       //draw the horizontal indicator.
  177.       PenPos := Point(cx-FButtonSize+2, cy);
  178.       LineTo(cx+FButtonSize-2, cy);
  179.       //draw the vertical indicator if the node is collapsed
  180.       if not Node.Expanded then
  181.       begin
  182.         PenPos := Point(cx, cy-FButtonSize+2);
  183.         LineTo(cx, cy+FButtonSize-2);
  184.       end;
  185.     end;
  186.         //now connect vertical lines of higher level nodes.
  187.     Node := Node.Parent;
  188.     while Node <> nil do
  189.     begin
  190.       cx := cx - TV.Indent;
  191.       if Node.GetNextSibling <> nil then
  192.       begin
  193.         PenPos := Point(cx, ARect.Top);
  194.         LineTo(cx, ARect.Bottom);
  195.       end;
  196.       Node := Node.Parent;
  197.     end;
  198.   end;
  199. end;
  200.  
  201. procedure TCustomDrawForm.DrawImage(NodeRect: TRect; ImageIndex: Integer);
  202. var
  203.   cy: Integer;
  204. begin
  205.   cy := NodeRect.Top + (NodeRect.Bottom - NodeRect.Top) div 2;
  206.   //center image in NodeRect.
  207.   ImageList.Draw(TV.Canvas, NodeRect.Left, cy - TV.Images.Height div 2,
  208.                  ImageIndex, True);
  209. end;
  210.  
  211. procedure TCustomDrawForm.TVCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  212.   State: TCustomDrawState; var DefaultDraw: Boolean);
  213. var
  214.   NodeRect: TRect;
  215. begin
  216.   with TV.Canvas do
  217.   begin
  218.     //If DefaultDraw it is true, any of the node's font properties can be
  219.     //changed. Note also that when DefaultDraw = True, Windows draws the
  220.     //buttons and ignores our font background colors, using instead the
  221.     //TreeView's Color property.
  222.     if cdsSelected in State then
  223.     begin
  224.       Font.Assign(SelectedFontDialog.Font);
  225.       Brush.Color := SelBkgColorDialog.Color;
  226.     end;
  227.  
  228.     DefaultDraw := FDefaultDrawItem;
  229.     //DefaultDraw = False means you have to handle all the item drawing yourself,
  230.     //including the buttons, lines, images, and text.
  231.     if not DefaultDraw then
  232.     begin
  233.       //draw the selection rect.
  234.       if cdsSelected in State then
  235.       begin
  236.         NodeRect := Node.DisplayRect(True);
  237.         FillRect(NodeRect);
  238.       end;
  239.       NodeRect := Node.DisplayRect(False);
  240.  
  241.       if None1.Checked then
  242.       //no bitmap, so paint in the background color.
  243.       begin
  244.         Brush.Color := BkgColorDialog.Color;
  245.         Brush.Style := FBrushStyle;
  246.         FillRect(NodeRect)
  247.       end
  248.       else
  249.         //don't paint over the background bitmap.
  250.         Brush.Style := bsClear;
  251.  
  252.       NodeRect.Left := NodeRect.Left + (Node.Level * TV.Indent);
  253.       //NodeRect.Left now represents the left-most portion of the expand button
  254.       DrawButton(NodeRect, Node);
  255.  
  256.       NodeRect.Left := NodeRect.Left + TV.Indent + FButtonSize;
  257.       //NodeRect.Left is now the leftmost portion of the image.
  258.       DrawImage(NodeRect, Node.ImageIndex);
  259.  
  260.       NodeRect.Left := NodeRect.Left + ImageList.Width;
  261.       //Now we are finally in a position to draw the text.
  262.  
  263.       TextOut(NodeRect.Left, NodeRect.Top, Node.Text);
  264.     end;
  265.   end;
  266. end;
  267.  
  268. procedure TCustomDrawForm.TVGetImageIndex(Sender: TObject; Node: TTreeNode);
  269. begin
  270.   if Node.HasChildren then
  271.     if Node.Expanded then
  272.       Node.ImageIndex := 3
  273.     else
  274.       Node.ImageIndex := 0
  275.   else
  276.     Node.ImageIndex := 1;
  277. end;
  278.  
  279. procedure TCustomDrawForm.TVGetSelectedIndex(Sender: TObject; Node: TTreeNode);
  280. begin
  281.   Node.SelectedIndex := Node.ImageIndex;
  282. end;
  283.  
  284. procedure TCustomDrawForm.Exit1Click(Sender: TObject);
  285. begin
  286.   Close;
  287. end;
  288.  
  289. procedure TCustomDrawForm.Selection1Click(Sender: TObject);
  290. begin
  291.   if SelectedFontDialog.Execute then
  292.     TV.Repaint;
  293. end;
  294.  
  295. procedure TCustomDrawForm.Color1Click(Sender: TObject);
  296. begin
  297.   if BkgColorDialog.Execute then
  298.     TV.Repaint;
  299. end;
  300.  
  301. procedure TCustomDrawForm.SelectionBackground1Click(Sender: TObject);
  302. begin
  303.   if SelBkgColorDialog.Execute then
  304.     TV.Repaint;
  305. end;
  306.  
  307. procedure TCustomDrawForm.Solid1Click(Sender: TObject);
  308. begin
  309.   with Sender as TMenuItem do
  310.   begin
  311.     FBrushStyle := TBrushStyle(Tag);
  312.     Checked := True;
  313.   end;
  314.   TV.Repaint;
  315. end;
  316.  
  317. procedure TCustomDrawForm.None1Click(Sender: TObject);
  318. begin
  319.   (Sender as TMenuItem).Checked := True;
  320.   TV.Repaint;
  321. end;
  322.  
  323. procedure TCustomDrawForm.OnCustomDraw1Click(Sender: TObject);
  324. begin
  325.   FDefaultDraw := not FDefaultDraw;
  326.   OnCustomDraw1.Checked := FDefaultDraw;
  327.   TV.Repaint;
  328. end;
  329.  
  330. procedure TCustomDrawForm.OnCustomDrawItem1Click(Sender: TObject);
  331. begin
  332.   FDefaultDrawItem := not FDefaultDrawItem;
  333.   OnCustomDrawItem1.Checked := FDefaultDrawItem;
  334.   TV.Repaint;
  335. end;
  336.  
  337. procedure TCustomDrawForm.TVExpanded(Sender: TObject; Node: TTreeNode);
  338. begin
  339.   TV.Repaint;
  340. end;
  341.  
  342. procedure TCustomDrawForm.ButtonColor1Click(Sender: TObject);
  343. begin
  344.   if ButtonColorDialog.Execute then TV.Repaint;
  345. end;
  346.  
  347. procedure TCustomDrawForm.ButtonSize1Click(Sender: TObject);
  348. var
  349.   S: string;
  350. begin
  351.   S := IntToStr(FButtonSize);
  352.   if InputQuery('Change button size', 'Enter new size', S) then
  353.     FButtonSize := StrToInt(S);
  354.   TV.Repaint;  
  355. end;
  356.  
  357. procedure TCustomDrawForm.Drawing1Click(Sender: TObject);
  358. begin
  359.   ButtonColor1.Enabled := not OnCustomDrawItem1.Checked;
  360.   ButtonSize1.Enabled := ButtonColor1.Enabled;
  361. end;
  362.  
  363. procedure TCustomDrawForm.Color2Click(Sender: TObject);
  364. begin
  365.   if TVColorDialog.Execute then
  366.   begin
  367.     TV.Color := TVColorDialog.Color;
  368.     TV.Repaint;
  369.   end;
  370. end;
  371.  
  372. procedure TCustomDrawForm.SetCustomDraw(Value: Boolean);
  373. begin
  374.   if not Value then
  375.   begin
  376.     TV.OnCustomDraw := nil;
  377.     TV.OnCustomDrawItem := nil;
  378.   end else
  379.   begin
  380.     TV.OnCustomDraw := Self.TVCustomDraw;
  381.     TV.OnCustomDrawItem := Self.TVCustomDrawItem;
  382.   end;
  383.   Drawing1.Enabled := Value;
  384.   TV.Repaint;
  385. end;
  386.  
  387. procedure TCustomDrawForm.CustomDraw1Click(Sender: TObject);
  388. begin
  389.   CustomDraw1.Checked := not CustomDraw1.Checked;
  390.   SetCustomDraw(CustomDraw1.Checked);
  391. end;
  392.  
  393. procedure TCustomDrawForm.Font2Click(Sender: TObject);
  394. begin
  395.   if TVFontDialog.Execute then
  396.     TV.Font.Assign(TVFontDialog.Font);
  397. end;
  398.  
  399. end.
  400.