Format

I need to format (a) single node(s) in ttreeview, (a) single line(s) in TListView, and TPageControl's tabs.

the kind of Format I need is to set background color and font(and it's color, ofcourse)

Please help
LVL 1
duke_nAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

LischkeCommented:
Well, no problem. Use the owner draw capabilites of the controls you mentioned. All three support this but with different parameters, so you have to write different handlers:

procedure TMainForm.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  with Sender do
  begin
    Canvas.Color := clRed;
    ...
    Canvas.TextOut(...);
    DefaultDraw := False;
  end;
end;

procedure TMainForm.ListView1CustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  with Sender do
  begin
    Canvas.Color := clRed;
    ...
    Canvas.TextOut(...);
    DefaultDraw := False;
  end;
end;

procedure TMainForm.PageControl1DrawTab(Control: TCustomTabControl;
  TabIndex: Integer; const Rect: TRect; Active: Boolean);
begin
  with Sender do
  begin
    Canvas.Color := clRed;
    ...
    Canvas.TextOut(...);
  end;
end;

Ciao, Mike
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
duke_nAuthor Commented:
So what you're saying, is that to make it's caption visible, I'll have to do something like this:

........
Canvas.TextOut(Control.Caption);
........
 
????



And what about treeview? I don't want to format the sender(TCostomtreeview) but the node(TTreeNode). Oh, and can I also edit the hints of individual treeview nodes?
0
LischkeCommented:
The TextOuts are only examples. For the tabs you would use the text according to the given tab index, but for the tree and list view I think setting forground color (FOnt.Color) and the background color (Canvas.Color) to arbitrary values should be enough (leave DefaultDraw = True then). You would do this depending on the item/node passed into the event handler.

For the hints this becomes much more complicated as this is performed by Windows. At least for the treeview I can give you a solution but this requires that you install my TreeNT control to replace the default tree view (see www.lischke-online.de/TreeNT.html).

Ciao, Mike
0
Introduction to R

R is considered the predominant language for data scientist and statisticians. Learn how to use R for your own data science projects.

duke_nAuthor Commented:
Oh. I Forgot.
My tabs are on the right side of the PageControl.

I don't get what you mean by "setting forground color (FOnt.Color) and the background color (Canvas.Color) to arbitrary values should be enough (leave DefaultDraw = True then)". If I do the setting to the treeview(or the listview) then the format of all the nodes(or items) changes..... whad'ya mean?
0
LischkeCommented:
You need to restrict the color changes to specific nodes, of course. Look at this code:

procedure TMainForm.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  with Sender as TTreeView do
  begin
    if Node.Level = 0 then
    begin
      if cdsHot in State then Canvas.Font.Style := [fsUnderline]
                         else Canvas.Font.Style := [];
      if cdsFocused in State then Canvas.Brush.Color := clBtnShadow
                             else Canvas.Brush.Color := clBtnHighlight;
    end
    else
      if Node.Level = 1 then
      begin
        Canvas.Font.Style := [];
        if cdsHot in State then Canvas.Brush.Color := clBtnFace
                           else
          if (cdsSelected in State) or Node.Expanded then Canvas.Brush.Color := clBtnHighlight
                                                     else Canvas.Brush.Color := clBtnFace;
      end;
  end;
end;

Ciao, Mike
0
duke_nAuthor Commented:
That's Xactly what I needed, muchacho, but what about the listview? and TPagecontrol(remember that the caption need to be 90 degrees rotated  because the tabposition is tpRight?)
0
LischkeCommented:
Mmh, duke, you don't make it easy, do you :-)? I think the paint of a listview item is very similar to that of a tree view node (except that you perhaps need to paint an icon which can be done with the usual image list methods). But for tab control you need specifc APIs to make rotated text. Look at this code:

procedure TMainForm.Button2Click(Sender: TObject);
var
  S: String;
  LogFont: TLogFont;
  FontHandle,
  SaveHandle: HFONT;

begin
  SaveHandle := Canvas.Font.Handle;
  GetObject(SaveHandle, SizeOf(LogFont), @LogFont);
  LogFont.lfEscapement := 2700;  // this is 270°
  LogFont.lfOrientation := 2700;
  FontHandle := CreateFontIndirect(LogFont);
  Canvas.Font.Handle := FontHandle;
  S := 'Vertical text?';
  TextOut(Canvas.Handle, 20, 10, PChar(S), Length(S));
  Canvas.Font.Handle := SaveHandle;
  DeleteObject(FontHandle);
end;

What happens is that the handle of the current font of the (form's) canvas is saved to restored it later. Then the properties of this font are read (GetObject) and two specific properties are changed (this is not possible using the VCL). The a new font is created with those properties and made active in the device context. After the text output the original font handle is restored and the newly created font deleted.

For your tabs you can actually create the vertical font once and select it when needed into the device context (in the custom draw event for the page control).

Ciao, Mike
0
duke_nAuthor Commented:
this draws something(perfectly horizontal) on my form.....
0
duke_nAuthor Commented:
(draws text, I mean)
0
duke_nAuthor Commented:
Oh, sorry, my bad.
the listview really does act similarly to the treeview in this aspect
0
LischkeCommented:
Ups, after the third comment I don't know any longer what you mean. Is it that the code for drawing vertical text does not work (I assume you have Win9x, under WinNT it works perfectly)?

Ciao, Mike
0
duke_nAuthor Commented:
OK.
from the beginnin'.
Your code for TTreeview and Tlistview works perfectly.

Your code for the tabs drew HORIZONTAL text on the FORM( at my machine, anyway).

Is there no way to hook it's canvas like we did with treeview and leave all the problems to itself? :)
0
LischkeCommented:
Of course is there a similar way. Set the OwnerDraw property of the page control to True and create an event handler for the OnDrawTab event like this:

procedure TMainForm.PageControl1DrawTab(Control: TCustomTabControl;
  TabIndex: Integer; const Rect: TRect; Active: Boolean);

var
  S: String;
  LogFont: TLogFont;
  R: TRect;

begin
  with Control do
  begin
    S := TPageControl(Control).Pages[TabIndex].Caption;
    GetObject(Canvas.Font.Handle, SizeOf(LogFont), @LogFont);
    LogFont.lfEscapement := 2700;  // this is 270°
    LogFont.lfOrientation := 2700;
    Canvas.Font.Handle := CreateFontIndirect(LogFont);
    R := Rect;
    if Active then Inc(R.Left, 4);
    Canvas.TextOut(R.Left + 14, R.Top + 8, S);
  end;
end;

This works fine for me, but I'm using WinNT. It should work with Win9x too, but I am not sure. So just try it out...

Ciao, Mike
0
duke_nAuthor Commented:
this does something spooky.
Kinda hard to explain...
it stops drawing the caption at all.
0
duke_nAuthor Commented:
Oh, got it!
it draws it in the orng place and not rotated
0
duke_nAuthor Commented:
and errrr.
it draws even active tabs like they are not active(this is confusing, I know. if ye want, I'll send you a screenshot)
0
LischkeCommented:
It *should* work. I don't know why it doesn't. Please send me your test project and I try running it on a machine here (public@lischke-online.de).

Ciao, Mike
0
duke_nAuthor Commented:
sent it...
0
LischkeCommented:
.. and I found the problem (although I had first to download one of the rar tools, why the heck don't you use a normal zipper as everyone?).

Not every font supports rotation. Try Arial instead of Courier for the tab control.

Ciao, Mike
0
duke_nAuthor Commented:
RAR compresses better and has some cool options like recovery record.
sorry fore the trouble
0
duke_nAuthor Commented:
Good.
It worx.

but thru my work I got two more Qs :
How to format a checkbox from a single Listitem's and how to hide a checkbox from one?

Yeah, Yeah, I know. I'm a b*tch. so if you want, I'll raise the points.
0
LischkeCommented:
Yes, raising the points is a fantastic idea :-))) Well, I will figure out also your latest problems and come back in a view minutes...

Ciao, Mike
0
LischkeCommented:
and here I am...:-)

As I have never done this kind of customdraw before I had to figure out some things which aren't obvious. The result is:

procedure TMainForm.ListView1CustomDrawItem(Sender: TCustomListView;
  Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);

var
  Check: TBitmap;
  R: TRect;
  AllowCheckBox: Boolean;

begin
  AllowCheckBox := Item.Index <> 1;
  with Sender do
  begin
    Canvas.Font := Font;
    if cdsSelected in State then
    begin
      Canvas.Brush.Color := clBtnShadow;
      Canvas.Font.Color := clWhite;
    end
    else
    begin
      Canvas.Brush.Color := clWindow;
    end;
    with Item do
      //ExtTextOut(Canvas.Handle, Position.X, Position.Y, ETO_OPAQUE, nil, PChar(Caption), Length(Caption), nil);
      Canvas.TextOut(Position.X, Position.Y, Caption);
    DefaultDraw := False;

    if CheckBoxes and AllowCheckBox then
    begin
      Check := TBitmap.Create;
      Check.Handle := LoadBitmap(0, PChar(OBM_CHECK));
      Check.Transparent := True;
      R := Rect(0, 0, Check.Width, Check.Height);
      OffsetRect(R, (Item.Position.X - Check.Width) div 2, Item.Position.Y + 1);
      DrawFrameControl(Canvas.Handle, R, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_MONO);
      // IMPORTANT: the following line sets the foreground color correctly otherwise the check mark is not shown
      Canvas.Font.Color := clBlack;
      if Item.Checked then Canvas.Draw(R.Left + 1, R.Top, Check);
      Check.Free;
    end;

  end;
end;


You need of course to adjust AllowCheckBox to your needs and I'd recomment to load the check bitmap only once instead every time an item is paintend.

I hope this is it finally...

Ciao, Mike
0
duke_nAuthor Commented:
It does horrible stuff when scrolling the list horizontally. Can't we hide it w/o "hurting" the listview data(I've got more than one column)
0
LischkeCommented:
I assume the item's position does not reflect the scrolling. I'd recommend that you retrive the scroll positions (GetScrollInfo) and apply them to the positions.

Soryy, I can't give you more advice here as we are already discussing stuff which weren't asked by your question, I spent already quite a long time on this question and you haven't raised the points. And even if you raise the points, I cannot spend the whole day just to figure out every little detail.

Sorry,

Ciao, Mike
0
duke_nAuthor Commented:
OK.
{I wanted to raise'em after I'll get a suitable answer}.
Then I will have to do some yankin' and bankin' myself :) (Yet yanking and banking with YOUR code, so I'm still raising the points)
0
duke_nAuthor Commented:
Adjusted points to 200
0
LischkeCommented:
Thank you for the points. I see you mean it honest. I had case where I spent several hours just to get a 50 points C grading, so I wanted to make sure... Sorry, if I sounded too rough.

I'm still here (or in any other question) to help you :-)

Ciao, Mike
0
duke_nAuthor Commented:
tha's OK, 'mano.
0
duke_nAuthor Commented:
Figured that one out!
I have now a imagelist with the images of Checked and Unchecked. I assign them to the listview items and if I wanta hide them I assign imageindex -1
0
duke_nAuthor Commented:
the problem is if I want to format them....

I want to use canvas.floodfill (couldn't find how to edit images directly in imagelist so I'm getting one into TBitmap, then editing and then "sending back"), but I dunno how to edit ImageList  item's transparent color and the bitmaps get a bit ugly
0
duke_nAuthor Commented:
maybe you know how to edit their transparent color(like I do on designtime when I add them)
0
duke_nAuthor Commented:
Oh.
I fugured that one out already too
0
LischkeCommented:
Wow, you sent quite a lot of messages. Unfortunately, I need a bit sleep from time to time :-) so I couldn't reply here. During the weekend I'm only one or two times per day looking through E-E so it might last until monday before you get some response from me...

Ciao, Mike
0
LischkeCommented:
Hi Duke,

sorry, but I lost the overview here. Could we open a new question?

Ciao, Mike
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.