user1642826
user1642826

Reputation: 229

C++ rapidly refresh desktop

I am trying to make a program currently that outputs a polygon to the desktop for a simple animation. The problem I am currently running into is that the animation gets an "onion" effect because the desktop isn't refreshing. I have searched for a method to refresh the desktop however because it's an animation, none of the solutions can refresh it fast enough. Below is an example of my code:

#include <iostream>
#include <Windows.h>
#include <math.h>
#include <Shlobj.h>


int main() {    
    //start ambrose
    POINT amby[5];
    POINT pos;
    /* hide console window */
    ShowWindow(FindWindowA("ConsoleWindowClass", NULL), false);
    /* Calling GetDC with argument 0 retrieves the desktop's DC */
    HDC hDC_Desktop = GetDC(0);

    //This is just an example of what I am doing

    for (int i = 0; i < 10000; i++) {

        pos.x = 600+sin(double(i)/50)*200;
        pos.y = 500+cos(double(i)/50)*200;
        amby[0].x = -10+pos.x;
        amby[0].y = -10+pos.y;
        amby[1].x = -50+pos.x;
        amby[1].y = -50+pos.y;
        amby[2].x = 50+pos.x;
        amby[2].y = -50+pos.y;

        Polygon(hDC_Desktop,amby, 3);
        Sleep(10);
    }
    //The method I was trying before that didn't work VVVVV
    //LPITEMIDLIST pidl;
    //SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidl);
    //SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,pidl,0);
    return 0;
}

Thanks

Edit

I have tried using invalidateRect as such:

...
for (int i = 0; i < 10000; i++) {

    pos.x = 600+sin(double(i)/50)*200;
    pos.y = 500+cos(double(i)/50)*200;
    amby[0].x = -10+pos.x;
    amby[0].y = -10+pos.y;
    amby[1].x = -50+pos.x;
    amby[1].y = -50+pos.y;
    amby[2].x = 50+pos.x;
    amby[2].y = -50+pos.y;

    Polygon(hDC_Desktop,amby, 3);
    InvalidateRect(GetDesktopWindow(),NULL, true);
    Sleep(10);
}
...

I am wondering if there is anyway to call WM_ERASEBKGND or WM_DISPLAYCHANGE to force a change. Does anyone know if there is a way to call these?

Upvotes: 0

Views: 1623

Answers (3)

MSalters
MSalters

Reputation: 179779

There's an easy solution, and that's to not actually draw on the desktop. Instead, create a transparent full-screen window. Since it's transparent, any pixel that you don't draw will show the desktop underneath. Hence, only your polygon pixels will hide the underlying desktop.

As a result, the desktop window never needs to be invalidated or repainted etc.

Upvotes: 1

nanda
nanda

Reputation: 804

I am not sure what you are trying to achieve. Let me just answer to problem of onion effect. A quick and dirty solution to erase what was drawn in the previous iteration could be to draw using XOR mode but the solution has a few downsides, like flicker and color could be arbitrary. A proper solution that would address both the downsides would be to do all the drawing in a memory DC and BitBlt the same to the screen.

Code for the quick and dirty solution would be -

SetROP2(hDC_Desktop,R2_XORPEN);
//This is just an example of what I am doing

for (int i = 0; i < 100; i++) 
{
    if(i!=0)
    {
        pos.x = 600+sin(double(i-1)/50)*200;
        pos.y = 500+cos(double(i-1)/50)*200;
        amby[0].x = -10+pos.x;
        amby[0].y = -10+pos.y;
        amby[1].x = -50+pos.x;
        amby[1].y = -50+pos.y;
        amby[2].x = 50+pos.x;
        amby[2].y = -50+pos.y;

                    Polygon(hDC_Desktop,amby, 3);
    }

    pos.x = 600+sin(double(i)/50)*200;
    pos.y = 500+cos(double(i)/50)*200;
    amby[0].x = -10+pos.x;
    amby[0].y = -10+pos.y;
    amby[1].x = -50+pos.x;
    amby[1].y = -50+pos.y;
    amby[2].x = 50+pos.x;
    amby[2].y = -50+pos.y;

    Polygon(hDC_Desktop,amby, 3);
    Sleep(10);
}

Upvotes: 2

Lucian
Lucian

Reputation: 3554

Why don't you use a transparent wnd.

class COverlayWnd : public CWnd
{
    DECLARE_DYNAMIC(COverlayWnd)

public:
    COverlayWnd();
    virtual ~COverlayWnd();

protected:
    afx_msg void OnPaint();
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    DECLARE_MESSAGE_MAP()
};

// OverlayWnd.cpp : implementation file
//

The implementation. Just move the window if you want animations to run all over the desktop.

#include "stdafx.h"

// COverlayWnd

IMPLEMENT_DYNAMIC(COverlayWnd, CWnd)

COverlayWnd::COverlayWnd()
{
}

COverlayWnd::~COverlayWnd()
{
}

BEGIN_MESSAGE_MAP(COverlayWnd, CWnd)
    ON_WM_PAINT()
    ON_WM_CREATE()
END_MESSAGE_MAP()


void COverlayWnd::OnPaint()
{
    CPaintDC dc(this);
    CRect rect;
    GetClientRect( &rect );
    dc.FillSolidRect(&rect, RGB(1,1,1));
    //paint other stuff that don't have RGB(1,1,1)

}


int COverlayWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    BOOL bRet = 0;

    bRet = ModifyStyleEx(0,WS_EX_LAYERED|WS_EX_TRANSPARENT);
    bRet = ModifyStyle(DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU,0);
    bRet = ModifyStyle(WS_POPUP,0);
    bRet = SetLayeredWindowAttributes(RGB(1,1,1),0,LWA_COLORKEY);
    //the RGB(1,1,1) is the transparent color 
    ASSERT(bRet);
    //this->EnableWindow(FALSE);

    return 0;
}

Upvotes: 0

Related Questions