Recent

Author Topic: [Solved] How to force the paint of form canvas? (FormPaint)  (Read 781 times)

Shebuka

  • Sr. Member
  • ****
  • Posts: 422
Hello, I'm drawing in the form's FormPain with Canvas.StretchDraw. To refresh I call Form1.Invalidate and in both LCLCarbon and LCLQt this is working flawlessly, but in LCLCocoa nothing happens. The FormPaint method is never called if I do any of Invalidate/Repaint/Update/PostMessage(LM_PAINT), it's only called if I resize the window.

How do I force the paint of the form's canvas in LCLCocoa?
« Last Edit: May 22, 2019, 06:38:07 pm by Shebuka »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2268
    • havefunsoft.com
Re: How to force the paint of form canvas? (FormPaint)
« Reply #1 on: May 20, 2019, 10:00:04 pm »
are you calling .Invalidate from a separate (non-main) thread?

Simple project. Form + button, with the following code words as expected.
(The rectangle would be repainted with a different color on every button click)
Code: Text  [Select]
  1. { TForm1 }
  2.  
  3. procedure TForm1.Button1Click(Sender: TObject);
  4. begin
  5.   Invalidate;
  6. end;
  7.  
  8. procedure TForm1.FormPaint(Sender: TObject);
  9. begin
  10.   Canvas.Brush.Color := random($FFFFFF+1);
  11.   Canvas.Brush.Style := bsSolid;;
  12.   Canvas.FillRect(0,0,100,100);
  13. end;  
  14.  
« Last Edit: May 20, 2019, 10:05:44 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

Shebuka

  • Sr. Member
  • ****
  • Posts: 422
Re: How to force the paint of form canvas? (FormPaint)
« Reply #2 on: May 21, 2019, 09:55:28 am »
Yes, I'm receiving data on a separate (non-main) thread and calling the .Invalidate on the forms global var. Works great on both LCLCarbon and LCLQt.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2268
    • havefunsoft.com
Re: How to force the paint of form canvas? (FormPaint)
« Reply #3 on: May 21, 2019, 03:44:06 pm »
Can you find a reference pointing that invalidate() is threadsafe?

so far, I'd suggest to use Synchronize() method to do the invalidation. It's expected work on LCLCarbon, LCLQt and LCLCocoa.

Here's Cocoa documentation regarding the invalidation:
Quote
If a secondary thread of an application wants to cause portions of the view to be redrawn on the main thread, it must not do so using methods like display, setNeedsDisplay:, setNeedsDisplayInRect:, or setViewsNeedDisplay:.

Instead, it should send a message to the main thread or call those methods using the performSelectorOnMainThread:withObject:waitUntilDone: method instead
LCL .Invalidate() is a direct call to setNeedDisplay().
While the use of Synchronize() would achieve what documentation suggests (to call invalidate in the main thread).
« Last Edit: May 21, 2019, 04:06:27 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

Shebuka

  • Sr. Member
  • ****
  • Posts: 422
Re: How to force the paint of form canvas? (FormPaint)
« Reply #4 on: May 21, 2019, 04:53:48 pm »
You are right, it doesn't say that it's threadsafe, but it says that it only informs the form to repaint and you can call it multiple times before the actual repaint on main thread happens. So I've supposed it's sending a message to the form and doesn't care what thread it's called from...

I can't use Synchronize(), the thread is in a dylib and I'm setting it a function to be called back when it has updated data I need.

Currently, I've tried to do a PostMessage to the form handle with a custom message (LM_USER + X) and when I get the message in the form I call Invalidate. It works, but if I open the application menu I don't receive any of my PostMessages until I close the menu. In LCLCarbon and LCLQt I'm still receiving my messages when the menu is opened. Is this a know LCLCocoa issue or is it intended? Can you suggest a better approach?

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2268
    • havefunsoft.com
Re: How to force the paint of form canvas? (FormPaint)
« Reply #5 on: May 21, 2019, 06:46:27 pm »
It works, but if I open the application menu I don't receive any of my PostMessages until I close the menu. In LCLCarbon and LCLQt I'm still receiving my messages when the menu is opened. Is this a know LCLCocoa issue or is it intended?
This can be resolved.
There was a similar issue reported recently.

upd: it should now work just fine with r61259 (trunk)
« Last Edit: May 21, 2019, 07:16:16 pm by skalogryz »
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

Shebuka

  • Sr. Member
  • ****
  • Posts: 422
Re: How to force the paint of form canvas? (FormPaint)
« Reply #6 on: May 22, 2019, 01:51:51 pm »
Ok. I've managed to rebuild the IDE from the trunk r61259 for cocoa x86_64.

Messages are now received but there is another similar problem when the menu is open: Timers are not firing.

update: just updated to r61270, the problem from above is still present.
« Last Edit: May 22, 2019, 02:00:38 pm by Shebuka »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2268
    • havefunsoft.com
Re: How to force the paint of form canvas? (FormPaint)
« Reply #7 on: May 22, 2019, 04:14:25 pm »
but there is another similar problem when the menu is open: Timers are not firing.
try r61271
Patron Cocoa Widgetset development https://www.patreon.com/skalogryz

Shebuka

  • Sr. Member
  • ****
  • Posts: 422
Re: How to force the paint of form canvas? (FormPaint)
« Reply #8 on: May 22, 2019, 06:37:49 pm »
It's working! :D

Thank you @skalogryz for help and solving this issue  ;)

p.s.: please, can you also look in the other my issue? https://forum.lazarus.freepascal.org/index.php?topic=45432