-3

I have some dynamically created listview components with dozens of items, and over 24 columns.

When i set some canvas properties (brush.color, for example) in the onCustomdrawXXX events, or onAdvancedCustomDrawXXX events of the listview, the application gets unstable and crashes.

First, some visual glitches start to appear (header not painting, artifacts in the listview), then the app goes unresponsive and crashes.

I was able to reproduce the problem with a design-time created listview too.

I have read this, but i don't want to ownerdraw the control.

Can anyone help me with this, please?

Update: the code

procedure TMainForm.listview1AdvancedCustomDrawItem(
  Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
  Stage: TCustomDrawStage; var DefaultDraw: Boolean);
begin

  FDefaultCanvasColor := clWindow;

  if Item.SubItems[1] = 'Test' then begin
     FDefaultCanvasColor := $66CCFFFF;
  end;

  // if i remove this line, everything is OK
  (Sender As TCustomListView).Canvas.Brush.Color := FDefaultCanvasColor;

end;

The visuals are presented above (controls getting unresponsive, artifacts on the controls), then crash (YourApp.exe stopped working standard windows error message).

2nd update

I wasn't able to reproduce the problem yet, but i'm working on it.


I ended up ownerdrawing the control (despite my reluctance), that works without problems.

I will still research this problem, and if i come up with the solution will let you know.

Andrew Barber
  • 39,603
  • 20
  • 94
  • 123
beerwin
  • 9,813
  • 6
  • 42
  • 57
  • You should show the code and the exact error that happens. – Devolus Jun 13 '13 at 13:12
  • The code is very simple, but if you want, here it is (see update). – beerwin Jun 13 '13 at 13:14
  • It's not a matter of me wanting it, it's more a matter of looking into the crystal sphere to see your problem. ;) – Devolus Jun 13 '13 at 13:24
  • Unfortunately graphics wont tell you much. The software being a company secret, i can't show you screenshots. – beerwin Jun 13 '13 at 13:26
  • 3
    @beerwin But you could make a demo app that should behave the same way. That should be simple since there's only a few lines of code that you deem to be pertinent. – David Heffernan Jun 13 '13 at 14:08
  • This is a legacy data processing application, and copies data between different applications through OLE. The listview is used to set chart properties, order, crosstab/frequency table output. It wasn't written by me, and contains all the bad practices a Delphi code can contain. Unfortunately, stripping down to it's barebones is impractical for me. There are 10000-ish lines of code without a single comment. – beerwin Jun 13 '13 at 15:19
  • That's just a terrible thing to say. As Ian explains, putting your code into a brand new project in D5 does not lead to a reproduction of your reported behaviour. You expect us to somehow work out what's going wrong but you are not prepared to put in the time to create a reproduction. Something is impractical here, and it would appear to be your expectations. – David Heffernan Jun 13 '13 at 15:24

2 Answers2

3

I had a similar issue when changing the Canvas.Font instead. Not so much a crash, but definitely some drawing artifacts and misbehavior. Turns out that after the drawing event handlers exit, TListView does not clean everything up correctly, and does not report back to Windows correctly. This is because while the drawing event handlers are running, TListView actually disables some of is internal TCanvas event handlers (TBrush.OnChange, TFont.OnChange, etc) that would normally have been called when changes are made. Those event handlers set a flag that TListView looks for. So obviously, no event handlers means no flag set. What I ended up doing is manually calling the TCanvas event handlers at the end of my drawing event handlers, and the problem went away.

I am not near my code right now, but I will post an example later.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    When I encountered something similar I asked this question which may be relevant: http://stackoverflow.com/questions/8192961/is-there-a-bug-in-the-delphi-list-view-control-when-using-custom-drawing – David Heffernan Jun 13 '13 at 14:58
  • This is the closest thing i have for an answer – beerwin Jun 13 '13 at 15:23
  • @beerwin If you had a real question then you'd have more chance of getting a real answer. – David Heffernan Jun 13 '13 at 15:24
  • 2
    This question is quiet real. I don't expect a full blown answer with teh codez, more likely this the kind of answer is what i expected ("i had a similar issue, and this is the info what i have found"). If you just want to close this question, feel free to do so. If there would be an option to delete my question i would have done so to avoid needless debate. – beerwin Jun 13 '13 at 15:44
  • 2
    The question isn't real until there's a concrete repro. In the question you state "I was able to reproduce the problem with a design-time created listview too." So give us that repro. – David Heffernan Jun 13 '13 at 15:55
2

i would suggesting making a copy of your form, and ripping things out until it works. Then moving forward and figuring out what broke it.

Because when i have the code:

procedure TForm1.FormCreate(Sender: TObject);

    procedure Add(Caption: string; SubItems: array of string);
    var
        item: TListItem;
        i: Integer;
    begin
        item := ListView1.Items.Add;
        item.Caption := Caption;
        for i := Low(SubItems) to High(SubItems) do
            item.SubItems.Add(SubItems[i]);
    end;
begin
    Add('I''ve', ['got',  'soul'            ]);
    Add('but',   ['i''m', 'not', 'a solider']);

    Add('I''ve', ['got',  'Test'            ]);
    Add('but',   ['i''m', 'not', 'a tester' ]);
end;

with the drawing code:

procedure TForm1.ListView1AdvancedCustomDrawSubItem(
  Sender: TCustomListView; Item: TListItem; SubItem: Integer;
  State: TCustomDrawState; Stage: TCustomDrawStage;
  var DefaultDraw: Boolean);
begin
    FDefaultCanvasColor := clWindow;

    if Item.SubItems[1] = 'Test' then
     FDefaultCanvasColor := $66CCFFFF;

    // if i remove this line, everything is OK
    (Sender As TCustomListView).Canvas.Brush.Color := FDefaultCanvasColor;
end;

and it renders fine:

enter image description here

Although, this is Delphi 5. The most handsomest of the Delphi's.


Edit: An old bit of advice from Peter Below, which is still in some of my drawing code:

You are making a common mistake: you assume that changing a controls Font property will have an immediate effect on the control.Canvas.Font. It does not, those two are completely different entities.
You can only rely on the Canvas.Font to be identical to the control.Font inside a paint event. For any use outside a paint event you have to do a:

control.Canvas.Font := Control.Font;  

before using the canvas for measurement etc..

--
Peter Below (TeamB)

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • This doesn't seem to answer the question either. Again it's more like a comment asking for a concrete repro. – David Heffernan Jun 13 '13 at 14:58
  • @DavidHeffernan No, the answer **is** to strip down the code. One might argue if that's something that Stackoverflow can help him with, but his answer **is** the act of cutting things down until he finds the problem. – Ian Boyd Jun 13 '13 at 15:06
  • 1
    I agree that's the way for the asker to proceed and solve the problem. Hence my comment to the question. But that's not an SO answer in the meaning of the act. As it stands I don't see how anyone can answer the question if the behaviour is not reproducible. And I'm not your downvoter FWIW. – David Heffernan Jun 13 '13 at 15:08
  • I don't change the font in the control (never has, i'm aware of these things) – beerwin Jun 13 '13 at 15:10
  • 1
    @IanBoyd Anyway, I'm giving you a +1 here because you do at least clearly describe the next step that needs to be taken. – David Heffernan Jun 13 '13 at 15:28
  • "The most handsomest of the Delphi's." :) – lurker Jun 13 '13 at 15:35