Recent

Author Topic: TListview; using OndrawItem and OnDrawSubItem are not working correctly.  (Read 3732 times)

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Still problems wit TListview when I want some different.
It;s a great component if you change nothing like colors and selection.
WP told me to het property hideselection to false. The selectbar will not dissapear. He's correct, but the Tlistview displays the selectbar as grey when there's no focus.

To make it permanent you have to use OnCustomDrawItem and OnCustomDrawSubItem. So I made a small demo with a listview on form and set it to vsReport. By creating a form, I fill the columns with data. So far so good.
Now I set property ownerdraw to true. Now I need OncustomDrawItem to get some text in TListview:
Code: Pascal  [Select][+][-]
  1.   r := Item.DisplayRect(drBounds);
  2.   listview1.Canvas.TextRect(r,r.Left + 5,r.Top + 1,'hallo');
  3.   defaultdraw := false;
  4.  
This works only for items, not subitems. It'als repainting the text when you place the mouse cursor on a item.
The rest of the subitems must be filed by  OnCustomDrawSubItem :
Code: Pascal  [Select][+][-]
  1.   r := Item.DisplayRectSubItem(subitem,drBounds);
  2.   listview1.Canvas.TextRect(r,r.Left + 5,r.Top + 1,'subhallo');
  3.   defaultdraw := false;
  4.  
But TListview shows nothing on screen on subitems. Even when I put a debu stop on the procedure it wil not stop.

My conclusion OnCustomDrawItem is filled with code, OnCustomDrawSubItem is not working.

If I delete OnCustomDrawItem the default items are showed into TListview and subitems are only on screen when I move the mouse cursor.

Very strange behaviour. There's is something not working correctly.

I only wat to have odd lines to color and a permanent selectbar with the same color when active / inactive

When I use this code in OnCustomDrawItem and TListview is inactive the whole listview will ne colored:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
  2.   Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
  3. var r : TRect;
  4. begin
  5.   if (cdsSelected in state) or  (cdsGrayed in state) then
  6.   begin
  7.     listview1.Canvas.Brush.Color := clRed;
  8.     r := Item.DisplayRect(drBounds);
  9.     listview1.canvas.FillRect(r);
  10.     listview1.Canvas.TextRect(r,r.Left + 5,r.Top + 1,'hallo');
  11.     defaultdraw := false;
  12.   end;
  13. end;
  14.  
another problem is aligning. I have listview with some numbers which are aligned to RightJustify.
I have a piece of code that runs only in OnDrawItem, but when a line is selected, all text aligned to right are put on left.
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

jamie

  • Hero Member
  • *****
  • Posts: 6130
Try setting your font.color…. its obviously the same as the background.

Set the font in the canvas before spitting out text..

Canvas.Font.Color := ....

etc
The only true wisdom is knowing you know nothing

wp

  • Hero Member
  • *****
  • Posts: 11916
I can confirm these observations. Pretty much confusing. It seems to be the same mess that I remember from the Delphi TListView...

Do I understand correctly that the reason for custom-drawing is that you want to see the selected item always in the highlight color even when the Listview does not have focus? And are you on Windows?

I played a lot with the Listview now, and could not find a solution for such a non-focused highlight color issue (on Windows). It seems as if the win32-widgetset is by-passing the OnCustomDrawItem event when the color of the non-focused selected cell is set.

But why don't you use a TStringGrid for your purpose? It is much easier to understand and can be configured to look like a TListview in report mode.

jamie

  • Hero Member
  • *****
  • Posts: 6130
I have some junk test code here..

vsList mode and I can get it to show the subitems but I don't have a very full understanding of what this  control is suppose to look like anyways...  >:(
 
 This is just a demo from my end;;

 I did notice the displayRectangle for the item seems to be the same as the SubItems ? I don't know if this is normal or not but I did some offset drawing.. This is just a hack demo.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.ListView1CustomDraw(Sender: TCustomListView;
  2.   const ARect: TRect; var DefaultDraw: Boolean);
  3. begin
  4.   With TListView(Sender)do
  5.    begin
  6.      Canvas.Brush.Color := clBlue;
  7.      Canvas.Brush.style := bsSolid;
  8.      Canvas.FillRect(AREct);
  9.    end;
  10. end;
  11.  
  12. procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
  13.   Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
  14. var
  15.   I:Integer;
  16.   R:TRect;
  17. begin
  18.   With TlistView(Sender) do
  19.    begin
  20.      Canvas.Font.Color := clRed;
  21.      Canvas.Brush.Style := bsclear;
  22.      Canvas.TextOut(Item.DisplayRect(drLabel).Left, Item.DisplayRect(drLabel).Top, Item.Caption);
  23.      canvas.Font.Color := clYellow;
  24.      For I :=0 To Item.SubItems.Count-1 do
  25.       begin
  26.        R := item.DisplayRectSubItem(I,drLabel);
  27.        R.Offset(50,I*Canvas.TextHeight('T'));
  28.       Canvas.TextOut(R.Left, R.Top, item.SubItems[I]);
  29.       End;
  30.      DefaultDraw := False;
  31.    end;
  32. end;                            
  33.  

 what I found is if you answer the DefaultDrawing := false in the first event it won't call the subitem event..
strange beans I guess.

The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6130
I can say beyond a doubt that this TlistView is totally screwed up! I don't remember it being this way ..

 The issue at hand is that once you set a DefaultDraw = False; the remaining other events won't get called.
 The returning flag set should not effect the other events.. It should only cancel the default drawing for that particular event.

 I can get the SubItemDraw event to call if I don't set the DefaultDraw to false on the CustomDrawItem.

 But if you allow it then the default drawing takes over and messes up your art work.

 you can do all of the drawing for both items within the OnCustomDrawItem. but you shouldn't have to do that because now you need to calculate the chords.

 I'll look at the source code.
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6130
Apparently someone had an after thought here..

Code: Pascal  [Select][+][-]
  1.  
  2.   case ATarget of
  3.     dtControl: if CustomDraw(ARect^, AStage) then Exit;
  4.     dtItem:    if CustomDrawItem(Items[AItem], AState, AStage) then Exit;
  5.     dtSubItem: if CustomDrawSubItem(Items[AItem], ASubItem, AState, AStage) then Exit;
  6.   end;
  7.  
  8.   // if we are here, a custom step returned false, so no default drawing
  9.   if AStage = cdPrePaint
  10.   then Result := [cdrSkipDefault];
  11. end;
  12.  
         
That is the end of the  "IntfCustomDraw......"

 if any one of the events returns false to cancel default drawing of that event it also cancels all remaining events.
                                                       
 don't you think it should continue the remainder set events ?

 I had thought this to work correctly at one time.. ..

Edit:

  The problem is up in the widget, there seems to be some issue with message handling of this control for customdraw..
I am inclined to believe that maybe MS has added a message or sequence to the NM_CUSTOMDRAW for the CDDS_XXXX pool because the way the code is written it only test for CDDS_ITEM and then CDDS_SUB, if those two fail then it assumes a the full control without testing the value.

  Also doing some reading it looks like a proper return message is needed for the OS to send the next paint request ..
 

« Last Edit: April 10, 2020, 04:22:09 am by jamie »
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 6130
Here's a nice article on the subject of customDrawing a Tlistview…


http://delphidabbler.com/articles?article=16

It basically explains a lot, whether the LCL follows this I don't know..
The only true wisdom is knowing you know nothing

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
It's a nice article, jamie and I have seen it earlier. I can test the demo in Lazarus to see whats happens. I also noticed in the article defaultdraw = false is never used.

@wp.
The look of view in TStringgrid is very different of TDBGrid. But in the first place I don't find that component nice to work.

But I know I can do a lot with this component. Even get my look of view like TListview. And I think I have to.
« Last Edit: April 12, 2020, 01:34:47 pm by mangakissa »
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

wp

  • Hero Member
  • *****
  • Posts: 11916
@wp.
The look of view in TStringgrid is very different of TDBGrid. But in the first place I don't find that component nice to work.
Why TDBGrid? I thought this discussion is about TListView, and I brought in TStringGrid. Nobody talked about DBGrid so far. Or am I lost once again?

jamie

  • Hero Member
  • *****
  • Posts: 6130
I found that the TlistView is not fully implemented for owner draw, it does not have the OnDrawHeader event so at this point all you can basically do is just the client area of it.

  Personally If you want to get to real graphics and cell control I like using the TDrawGrid that seems to work very nicely. If you need strings then the StringGrid like @Wp stated.. but that has a lot o baggage that you need to work around with but it does work.

 The Grid can be fully controlled for drawing because it does not live most of its life inside of the OS but in your app instead.
   
  I suppose the Tlistview can be explored for the needed events but that would also mean the other widgets would need updating too.. Most likely less of an issue outside of WS32 they draw it all.

The only true wisdom is knowing you know nothing

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Why TDBGrid? I thought this discussion is about TListView, and I brought in TStringGrid. Nobody talked about DBGrid so far. Or am I lost once again?
Normally I use DBGrid to show data with a dataset. Now I have an object and shows data in listview. Like dbgrid I only show data, not modify it. That's why I use listview. Its clean and nice to see in dafault mode. But changing some things is not so yeasy at it should be.

Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

 

TinyPortal © 2005-2018