?
Solved

TTreeView, OnCustomDrawItem how to proceed....

Posted on 2006-05-16
7
Medium Priority
?
1,355 Views
Last Modified: 2012-08-14
Hello everyone,
I'm trying to develop an application that handles diffrent records in a database(n-tire). The database have a field named "folder" which indicates the named place for the record. The application have a TreeView placed on the left side of the form, and the nodes are named after the "folders" in the database. (like March 2006, April 2006). All records can have different "status" (like open/closed) and I would like to display the count of records having the status "open" for each folder in the treview, with bolded text and the count of open records in blue. (jus like MS Outlook). I have a timer on the application checking against the server for new records continously, so this feature can not be a part of the actual treeviews events (like OnCustomDrawItem, I've tried that one but couldn't manage to forece the repainting of each node without messing with the treeview). Below You can find the code that I've tried so far, but as I mentioned before, it works as long as You play with the TreeView not the background functionality Im looking for.

procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
  bmp: TBitMap;
  s: string;
  pt: TPoint;
  r: TRect;
  DC: HWND;
begin
  if Node.Text = 'Inbox' then
  begin
    s := '('+IntToStr(CDS.RecordCount)+')';
    Sender.Canvas.Font.Style := [fsBold];
    r := Node.DisplayRect(true);
    bmp := TBitmap.Create;
    bmp.Width := Canvas.TextWidth(s);
    bmp.Height := Canvas.TextHeight(S);
    bmp.Canvas.Font.Color := clBlue;
    bmp.Canvas.Brush.Style := bsClear;
    bmp.Canvas.TextOut(0, 0, s);
    Pt.x := r.Left + sender.Canvas.TextWidth(Node.Text)+8;
    Pt.y := r.Top + 2;
    DC := GetDC(sender.Handle);
    BitBlt(DC, pt.x, pt.y, BMP.Width, BMP.Height, BMP.Canvas.Handle, 0, 0, SRCCOPY);
    bmp.Free;
    ReleaseDC(sender.Handle, DC);
    DefaultDraw := True;
  end;
end;

The solution would be to manage the forced repainting and/or develop a totally new feature I think. Any suggestions?

Kind regards,
-Hokki
0
Comment
Question by:hakanfa
  • 3
  • 2
6 Comments
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 16695481
in the timer that changes the counts etc, you could call
treeview1.repaint;
at the end
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 16696205
ah wait, i remember the problems now
because of the treeview canvas problem (where it creates a new "unrelated" font if you access the canvas, thus corrupting subsequent nodes displayed in the tree)
You will have to draw everything manually (link lines, selected region box etc)
if you wish to use different font properties (in your case fsBold also) for different nodes.
It is even worse if you wish to use different fonts on the same node (which you are doing)
What you are doing with the TBitmap is ok, but you may have to extend it to draw the node.text also, and the aforementioned link-lines, etc)
http://www.delphipages.com/news/detaildocs.cfm?ID=159
shows how to do the display, similar to what you do)
but I do not have an example of doing the link lines.
The easy "trick" to do this, is to draw the dotted lines in a 16x16 image, and load them into a TImageList.
You can then just use the "StateImage" property to display the appropriate one.
(Treeview1.StateImages := imagelist1; Node.StateIndex := 2;)
This is also handy if you want to have different coloured link lines, or something else

Another solution I have used, when TTreeview does not allow me to do formatting how I like, is the VirtualTreeview
http://www.delphi-gems.com/VirtualTreeview/VT.php

or TreeNT may be able to do this correctly, but i haven't tried it, and it is discontinued (same author i think, so probably replaced by virtual treeview)
http://www.delphi-gems.com/TreeNT.php

0
 

Author Comment

by:hakanfa
ID: 16696370
Hello, and thank you for a quick reply,
Actually the code that i mentioned works fine, the thing is that i would like to do the painting with an external procedure not an event from the
TreeView. The TreeView.Repaint or TreeView.Refresh doesn't trigger the OnDrawItem for some reasons, so the only way for the moment
is a)calling LockWindowsUpdate or b) reload the TreeView.(neither of these are acceptable). I actually think that I have the solution, but have to try it a few more times before I can be sure. I'll revert with details later.All idea's/thoughts are welcome.

-Hokki
 
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 17

Expert Comment

by:TheRealLoki
ID: 16696463
hmm, the repaint works here
I set up  :-
s := '('+IntToStr(somecount)+')';
in the OnCustomDrawItem event
...
and in the ontimer event, I have
somecount := somecount + 1;
treeview1.repaint;
occurring every second

and I am getting the "Inbox" node repainting fine, I am still able to open/close branches etc while this is working
0
 

Author Comment

by:hakanfa
ID: 16788230
Hello again.. still working on the project and found a nice solution for my problem. The following code works fine, though another problem occurred.
This works fine:

function GetNodeByText
(ATree : TTreeView; AValue:String;
 AVisible: Boolean): TTreeNode;
var
    Node: TTreeNode;
begin
  Result := nil;
  if ATree.Items.Count = 0 then Exit;
  Node := ATree.Items[0];
  while Node <> nil do
  begin
    if Node.Text = AValue then
    begin
      Result := Node;
      if AVisible then
        Result.MakeVisible;
      Break;
    end;
    Node := Node.GetNext;
  end;
end;


then...
In the treeviews OnCustomDrawItem the code I mentioned above..

then..
For example Button click..
RedrawWindow(GetNodeByText(TreeView1,'Inbox',true).Handle, @R, 0, RDW_FRAME or RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOCHILDREN);

Put the above code in some event/procedure when You need to update the specific node.. Then You do not need the Timer...

The problem that occurred is: When You drag items to the TreeView (like when you move items in Outlook) the painting of the specific node doesn’t work (the focus drawing when You drag items over a specific node). I've tried to make a simple demo just painting each node with bold text and this problem occurs even then.

procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  Sender.Canvas.Font.Style := [fsBold];
  DefaultDraw:=True;
end;

Here’s the dfm

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 361
  ClientWidth = 341
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object TreeView1: TTreeView
    Left = 8
    Top = 8
    Width = 145
    Height = 345
    DragMode = dmAutomatic
    Indent = 19
    TabOrder = 0
    OnCustomDrawItem = TreeView1CustomDrawItem
    OnDragOver = TreeView1DragOver
    Items.NodeData = {
      01040000002B0000000000000000000000FFFFFFFFFFFFFFFF00000000000000
      0009540065007300740069006E006700200031002B0000000000000000000000
      FFFFFFFFFFFFFFFF000000000000000009540065007300740069006E00670020
      0032002B0000000000000000000000FFFFFFFFFFFFFFFF000000000000000009
      540065007300740069006E006700200033002B0000000000000000000000FFFF
      FFFFFFFFFFFF000000000000000009540065007300740069006E006700200034
      00}
  end
  object TreeView2: TTreeView
    Left = 176
    Top = 8
    Width = 145
    Height = 345
    DragMode = dmAutomatic
    Indent = 19
    TabOrder = 1
    OnCustomDrawItem = TreeView1CustomDrawItem
    Items.NodeData = {
      01040000002B0000000000000000000000FFFFFFFFFFFFFFFF00000000000000
      0009540065007300740069006E006700200031002B0000000000000000000000
      FFFFFFFFFFFFFFFF000000000000000009540065007300740069006E00670020
      0032002B0000000000000000000000FFFFFFFFFFFFFFFF000000000000000009
      540065007300740069006E006700200033002B0000000000000000000000FFFF
      FFFFFFFFFFFF000000000000000009540065007300740069006E006700200034
      00}
  end
end

and the Unit

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    TreeView2: TTreeView;
    procedure TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure TreeView1CustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
      State: TCustomDrawState; var DefaultDraw: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  Sender.Canvas.Font.Style := [fsBold];
  DefaultDraw:=True;
end;


procedure TForm1.TreeView1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
 if Sender.ClassName = Source.ClassName then
  Accept:=True;
end;
end.

Any ideas?

-Hokki

0
 
LVL 1

Accepted Solution

by:
Computer101 earned 0 total points
ID: 17695879
PAQed with points refunded (500)

Computer101
EE Admin
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Suggested Courses
Course of the Month15 days, left to enroll

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question