Animation with VCL Component (WM_PAINT)

317 views Asked by At

The problem is OpenGL animation stops while any mouse button is clicked on the TForm component (border, caption ..). As soon as the mouse button released the animation goes on.

// Drawing Scene 
 void TMainForm::DrawGLScene()
{
    glClearColor(1,1,1,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    DrawFigure();
    SwapBuffers(hDC);
}

// Catching WM_PAINT 
LRESULT CALLBACK NewWindowProcPanel3D(HWND hWnd, UINT msg, WPARAM w, LPARAM l)
{
    switch (msg)
    {
        case WM_ERASEBKGND :
        {
            return 1;
        }
        case WM_PAINT :
        {
            MainForm->DrawGLScene();
        }
        default: return CallWindowProc((FARPROC)MainForm->OldWindowProcPanel3D,
            hWnd, msg, w, l);
    }
    return 0;
}

// Creating OldWindowProcPanel3D -
 void __fastcall TMainForm::FormCreate(TObject *Sender)
{
    OldWindowProcPanel3D = (WNDPROC)SetWindowLong(Panel3D->Handle,
        GWL_WNDPROC, (long)NewWindowProcPanel3D);
}

// --------- *.h :
class TMainForm : public TForm
{
    private:
       HDC hDC;
    public:
        WNDPROC OldWindowProcPanel3D;
}

// Generation event WM_PAINT 
 void TMainForm::UpdateScene()
{
    InvalidateRect(Panel3D->Handle, NULL, false);
}

// Animation code ( turn on 'animation' if RadioButton is chosen) 
 void __fastcall TMainForm::RadioGroupClick(TObject *Sender)
{
    if (RadioGroup->ItemIndex == 0)
       animation = false;
    else if (RadioGroup->ItemIndex == 1)
        animation = true;
     if (animation)
    {
        while (animation)
       {
            Application->ProcessMessages();
            UpdateScene();
        }
    }
}

What is to be done not to stop animation while changing sizes of the form, any usefull links?

1

There are 1 answers

0
Remy Lebeau On

That is because your main message loop is blocked and a secondary message loop is running while the window is being dragged/resized. The same thing happens when menus are active, modal dialogs are shown, etc. There is nothing you can do about that, that is simply how Windows operates.

BTW, assuming Panel3D is aTPanelor similar VCL control, you should subclass itsWindowProcproperty instead ofSetWindowsLong(), since theTWinControl::Handle` property is not persistent.

And you need to get rid of your use of Application->ProcessMessages() altogether. Never call that directly unless absolutely necessary.

Try this instead:

class TMainForm : public TForm
{
private:
    HDC hDC;
    bool animation;
    TWndMethod OldWindowProcPanel3D;
    void DrawGLScene();
    void __fastcall NewWindowProcPanel3D(TMessage &Message);
public:
    __fastcall TMainForm(TComponent *Owner);
};

// Creating OldWindowProcPanel3D -
__fastcall TMainForm::TMainForm(TComponent *Owner)
    : TForm(Owner)
{
    OldWindowProcPanel3D = Panel3D->WindowProc;
    Panel3D->WindowProc = &NewWindowProcPanel3D;
}

// Drawing Scene 
void TMainForm::DrawGLScene()
{
    glClearColor(1,1,1,1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    DrawFigure();
    SwapBuffers(hDC);
}

// Catching WM_PAINT 
void __fastcall TMainForm::NewWindowProcPanel3D(TMessage &Message)
{
    switch (Message.Msg)
    {
        case WM_ERASEBKGND :
        {
            Message.Result = 1;
            break;
        }

        case WM_PAINT :
        {
            DrawGLScene();
            if (animation)
                UpdateScene();
            break;
        }

        default:
        {
            OldWindowProcPanel3D(Message);
            break;
        }
    }
}

// Generation event WM_PAINT 
void TMainForm::UpdateScene()
{
    Panel3D->Invalidate();
}

// Animation code ( turn on 'animation' if RadioButton is chosen) 
void __fastcall TMainForm::RadioGroupClick(TObject *Sender)
{
    if (RadioGroup->ItemIndex == 0)
        animation = false;
    else if (RadioGroup->ItemIndex == 1)
        animation = true;

    if (animation)
        UpdateScene();
}