Recent

Author Topic: [windows] Eliminating form flicker when form is dragged?  (Read 8503 times)

Michaela Joy

  • New Member
  • *
  • Posts: 24
[windows] Eliminating form flicker when form is dragged?
« on: May 04, 2015, 10:19:24 pm »
Hi,
I did my best to search (both on line and in this forum) before asking my question, and I did not find anything that related to my question.

So, here goes...

I am building a pascal project (originally written in Delphi 7 / working). I have a single form on which I am drawing a ruler. I noticed flicker when my form was dragged.

These are the steps that I've taken so far.

1) In TForm1.FormCreate, I have set the form DoubleBuffered to True

I had to be do it like this, because the property "DoubleBuffered" is not exposed in TForm.
Code: [Select]
(Self as TWinControl).DoubleBuffered := True;

I have also subclassed the WM_ERASEBKGND message as follows

Code: [Select]
procedure TForm1.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
begin
Msg.Result := 1;
end;


I have set the form up so that it could be dragged by the client area, by subclassing the WM_NCHITTEST message.
The GetMouseExclusionZone() function simply tells me if I'm sizing the rule or dragging it.
Code: [Select]
if Msg.Result = htClient then
begin
if (Windows.GetAsyncKeyState(VK_LBUTTON) and $8000) <> 0 then
begin
if GetMouseExclusionZone(Msg.XPos,Msg.YPos) <> 0 then
Msg.Result := htClient
else
Msg.Result := htCaption;
end;
end;

I am handling the CreateParams like this

Code: [Select]
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
end;

When I drag the form around with the mouse, the form flickers (i.e. white ghosting where the form used to be, which disappears when you stop moving the form)

If I let Windows set up visual effects via the Control Panel, it sets up a theme, which makes the flickering go away. Setting Visual effects up for max performance causes the flicker.
The -exact- same code in Delphi 7 works fine with any of the windows visual setting.

I have used an off-screen bitmap to do my own buffered drawing, but the form still flickers when dragged.

Has anybody had this problem? If so, How did you solve it?

Thanks in advance,
:MJ

PS:
My version of Lazarus is 1.2.6
Date 2014-10-11
FPC 2.6.4
SVN revision 46529

« Last Edit: May 04, 2015, 10:41:01 pm by Michaela Joy »

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #1 on: May 04, 2015, 11:22:45 pm »
try to create a tpanel descendant and draw in their paint event.

and also set doublebuffered for it.

edit: sorry i not readed well...

ive reported that in bugtracker: im not the only one seeing shadows here: finally!

it can not be solved or something like that... find it yourself in bugtracker (is really old bug report)
« Last Edit: May 04, 2015, 11:26:46 pm by 007 »

Never

  • Sr. Member
  • ****
  • Posts: 409
  • OS:Win7 64bit / Lazarus 1.4
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #2 on: May 04, 2015, 11:25:12 pm »
-- your best bet for drag and drop is lockwindowupdate win api ex: lock-->LockWindowUpdate(yourform.Handle) / unlock LockWindowUpdate(0);
you can also try
-- begin/end update
-- sendmessage with WM_SetRedraw
ex :lock --> SendMessage(yourform.Handle, WM_SETREDRAW, 0, 0); / unlock SendMessage(yourform.Handle, WM_SETREDRAW, 1, 0)
with send message you have to redraw the window after unlock

Νέπε Λάζαρε λάγγεψων οξωκά ο φίλοσ'ς αραεύσε

Michaela Joy

  • New Member
  • *
  • Posts: 24
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #3 on: May 05, 2015, 01:48:29 am »
@007: Thanks for your reply, but the TPanel did not prove to be a viable solution. The problem, as it seems to present itself, is in the underlying mechanism used to render the TForm in Windows.

@Never: Thanks for replying, but the problem has nothing to do with Drag and Drop. :) There's a problem with the way a TForm is drawn when it is dragged across the screen. I suspect that the draw rectangle is not sized correctly when the TForm is dragged across the screen. I haven't done a comparison of the FPC / Lazarus forms unit vs. Delphi, but I suspect that something is wrong there.

:MJ
« Last Edit: May 05, 2015, 01:54:27 am by Michaela Joy »

lainz

  • Hero Member
  • *****
  • Posts: 4468
    • https://lainz.github.io/

Michaela Joy

  • New Member
  • *
  • Posts: 24
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #5 on: May 05, 2015, 04:23:47 am »
@007: So I'll have to live with it, I guess. :)

I found that compiling without debug info does make things better, although I will have to test to see if the reported bug appears without debug info enabled.

Thanks for all your help. :)

:MJ

Never

  • Sr. Member
  • ****
  • Posts: 409
  • OS:Win7 64bit / Lazarus 1.4
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #6 on: May 05, 2015, 08:32:42 am »
@ Michaela Joy
Quote
Thanks for replying, but the problem has nothing to do with Drag and Drop.
i didn't mention drag /drop as the source of the problem
just state that if this is the current operation then lockwindowupdate is the best way to go
it might not be if the flickering occurs under othe  conditions
Νέπε Λάζαρε λάγγεψων οξωκά ο φίλοσ'ς αραεύσε

lagprogramming

  • Sr. Member
  • ****
  • Posts: 405
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #7 on: May 05, 2015, 10:25:12 am »
@Michaela Joy
I'm not sure I understand the situation from your previous posts.
First of all I would like you to be sure that you compare the application, not the IDE. In an attempt to explain better, here it goes:
1) If you don't run the binary build file(F9), instead you just move the form in designing state, the comparison is done exclusivly between IDEs and not between built applications.
2) If you run the binary application from the IDEs(F9) and you let them in the background, again you're influenced by the IDEs. Why, because Lazarus has different code that has to be run in order to repaint it's windows, compared to Delphi. This means that if you move around the form of the same binary application over Lazarus and over Delphi, different repainting intervals(might lead to flicker) are expected to appear. Can you try comparing the binary files built by you over a neutral background(like an empty desktop for example)?
3) If indeed, the flicker comes from the binary file you may send me a PM. Why don't you use Lazarus 1.4.0!?

Michaela Joy

  • New Member
  • *
  • Posts: 24
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #8 on: May 05, 2015, 03:44:53 pm »
Quote from: Never
your best bet for drag and drop is lockwindowupdate win api ex: lock-->LockWindowUpdate(yourform.Handle) / unlock LockWindowUpdate(0);
you can also try
-- begin/end update
-- sendmessage with WM_SetRedraw
ex :lock --> SendMessage(yourform.Handle, WM_SETREDRAW, 0, 0); / unlock SendMessage(yourform.Handle, WM_SETREDRAW, 1, 0)
with send message you have to redraw the window after unlock

@Never: In your post, it looks like you're mentioning drag and drop to me.  As I said, I appreciate the fact that you tried to help.

@lagprogramming:
Quote
I'm not sure I understand the situation from your previous posts.

As I said, I have a form set up to allow me to drag it around the screen. When I drag it across a black background, white ghosting appears around the form when it is moved. The faster the form is moved, the more pronounced the effect.

Quote
If you don't run the binary build file(F9), instead you just move the form in designing state, the comparison is done exclusively between IDEs and not between built applications.

This is -NOT- an IDE problem; I am not saying that. This problem occurs when the executable is running. removing debug info does help a little bit. If you run the exe from the IDE with debug information installed, it slows down even more. But, as I said, that's to be expected as debugging requires monitoring of the application.

Quote
If you run the binary application from the IDEs(F9) and you let them in the background, again you're influenced by the IDEs. Why, because Lazarus has different code that has to be run in order to repaint it's windows, compared to Delphi.
I understand this. I have looked at Forms.pas of both Delphi and FPC. I also understand that Lazarus / FPC is cross-platform, so the difference is understandable.

Quote
This means that if you move around the form of the same binary application over Lazarus and over Delphi, different repainting intervals(might lead to flicker) are expected to appear. Can you try comparing the binary files built by you over a neutral background(like an empty desktop for example)?

The form flickers wherever it's dragged. It's easier to see when the background is dark or black, but it's visible anywhere on the screen.

Quote
If indeed, the flicker comes from the binary file you may send me a PM.

I will try to create a simple example, demonstrating the effect I am seeing, and I will post it here. Hopefully, this will make it easier for you (and anyone else) to try and diagnose the problem.

Quote
Why don't you use Lazarus 1.4.0!?

This is what I downloaded from the Lazarus 1.4 announcement post. Or, what I -thought- I downloaded.

:MJ

Michaela Joy

  • New Member
  • *
  • Posts: 24
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #9 on: May 07, 2015, 09:12:33 pm »
Update: I build an almost identical application using TDM-GCC. The Window behaved -exactly- the same as the Lazarus / FPC version  :-[

After some investigation, I found that LockWindowUpdate() was indeed the answer (Thanks Nowhere. :) )
What I did was respond to the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages. The result: It worked flawlessly.

On WM_ENTERSIZEMOVE:
LockWindowUpdate(hwnd)

On WM_EXITSIZEMOVE:
LockWindowUpdate(0);

However:
I proceeded to subclass the messages in Lazarus / FPC using the standard way of subclassing.

I declared these in the Form

   procedure WMEnterSizeMove(var Msg: TMessage); message WM_ENTERSIZEMOVE;
   procedure WMExitSizeMove(var Msg: TMessage); message WM_EXITSIZEMOVE;

In the resulting message handlers, I added the -exact- same code and, much to my chagrin,  nothing happened.

I'm guessing that I'll have to find another way to subclass the Forms' window?

:MJ

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #10 on: May 08, 2015, 12:43:40 pm »
You need to create your own message handler subroutine for your window using GetWindowLongPtr /SetWindowLongPtr Windows API functions.

Michaela Joy

  • New Member
  • *
  • Posts: 24
Re: [windows] Eliminating form flicker when form is dragged?
« Reply #11 on: June 30, 2015, 03:26:57 am »
Okay, so here's the final solution that works well.
Hopefully this will help others.

Code: [Select]
implementation

{$R *.lfm}

var
  OldWndProc: WNDPROC;    // The old Window procedure...
  WindowLocked: Boolean = FALSE;   // A flag used to indicate whether or not we've locked the window.

function Form1WndCallback(hwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall;
begin
case uMsg of
    WM_ENTERSIZEMOVE:
    begin
           if hwnd = Form1.Handle then
           begin
                 WindowLocked := TRUE;
                 LockWindowUpdate(hwnd);
           end;
           Result := 0;
           Exit;
    end;

    WM_EXITSIZEMOVE:
    begin
          if WindowLocked = TRUE then
          begin
               WindowLocked := FALSE;
               LockWindowUpdate(0);
               if hwnd = Form1.Handle then
                      Form1.Repaint;
          end;
        Result := 0;
        Exit;

        WM_MOVING:
             if WindowLocked = TRUE then
             begin
                     LockWindowUpdate(0);
                      // Repaint any windows that need to be repainted while the form is moving...
      LockWindowUpdate(hwnd);
             end;
        break;
end;
Result := CallWindowProc(OldWndProc,hwnd,uMsg,WParam,LParam);
end;


procedure TForm1.FormCreate(Sender:TObject);
begin
{$hints off}
OldWndProc := Windows.WNDPROC(SetWindowLongPtr(Form1.Handle,GWL_WNDPROC,PtrInt(@Form1WndCallback)));
{$hints on}
end;


procedure TForm1.FormDestroy(Sender:TObject);
begin
{$hints off}
SetWindowLongPtr(Form1.Handle,GWL_WNDPROC,PtrInt(OldWndProc));
{$hints on}
end;

procedure TForm1.WMEraseBkgnd(var Msg: TWMEraseBkgnd);
begin
Msg.Result := 1;
end;


EDIT: I added the WM_MOVING code to facilitate child / sibling windows being repainted. Otherwise, they do not repaint at all...

Thanks to everyone who helped. :)

:MJ
« Last Edit: June 30, 2015, 09:11:08 pm by Michaela Joy »

 

TinyPortal © 2005-2018