С++ быстро обновить рабочий стол

В настоящее время я пытаюсь создать программу, которая выводит многоугольник на рабочий стол для простой анимации. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что анимация получает эффект лука, потому что рабочий стол не обновляется. Я искал способ обновить рабочий стол, однако, поскольку это анимация, ни одно из решений не может обновить его достаточно быстро. Ниже приведен пример моего кода:

#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;
}

Спасибо

Редактировать

Я пытался использовать invalidateRect как таковой:

...
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);
}
...

Мне интересно, можно ли каким-либо образом вызвать WM_ERASEBKGND или WM_DISPLAYCHANGE, чтобы принудительно внести изменения. Кто-нибудь знает, есть ли способ вызвать их?


person user1642826    schedule 30.10.2012    source источник
comment
Для этого нужен дополнительный тег, так как простой C++ не может рисовать многоугольники.   -  person Benjamin Bannier    schedule 30.10.2012
comment
Похоже на Windows — я добавил тег.   -  person Paul R    schedule 30.10.2012
comment
С какой стати вы рисуете на рабочий стол, а не в своем собственном окне? Почему вы начинаете с того, что прячете случайное окно консоли?   -  person hmakholm left over Monica    schedule 30.10.2012
comment
Программа запускается в окне консоли, поэтому скрывает это. Он использует window.h для рисования. Причина, по которой я рисую на рабочем столе, заключается в том, что у меня может быть анимация, не привязанная к окну. Спасибо, что добавили этот тег, Павел.   -  person user1642826    schedule 30.10.2012
comment
Что ж, вы можете использовать InvalidateRect для принудительного рисования, но у вас нет рабочего стола, поэтому использовать его таким образом просто неправильно.   -  person Retired Ninja    schedule 30.10.2012
comment
@ user1642826: Вы не скрываете окно консоли своей программы — вы скрываете любое случайное окно консоли, которое FindWindow находит для вас — которое может быть тем, в котором запущена ваша программа, а может и не быть . Но почему в вашей программе вообще есть консольное окно, если все, что вы хотите сделать с ним, это скрыть его?   -  person hmakholm left over Monica    schedule 31.10.2012


Ответы (3)


Я не уверен, чего вы пытаетесь достичь. Позвольте мне просто ответить на проблему эффекта лука. Быстрое и грязное решение стереть то, что было нарисовано в предыдущей итерации, могло бы состоять в рисовании с использованием режима XOR, но у этого решения есть несколько недостатков, например, мерцание и цвет могут быть произвольными. Правильным решением, которое устранило бы оба недостатка, было бы выполнение всех рисунков в контроллере домена памяти и BitBlt одинаково на экране.

Код для быстрого и грязного решения будет -

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);
}
person nanda    schedule 30.10.2012
comment
Для более сложных объектов это не работает. Хотя при поиске этой функции я нашел несколько функций, которые хочу попробовать. Я нашел один, который работает, PaintDesktop(hDC_Desktop); однако он удаляет все элементы рабочего стола. (папки, панель запуска и т. д.) - person user1642826; 30.10.2012
comment
Просто добавлю, что после некоторых экспериментов я бы рекомендовал SetROP2(hDC_Desktop,R2_NOTXORPEN); , так как это устраняет проблему цвета. А если сделать инверт после новой пасты то меньше не будет мигать. - person user1642826; 31.10.2012

Есть простое решение — не рисовать на рабочем столе. Вместо этого создайте прозрачное полноэкранное окно. Поскольку он прозрачен, любой пиксель, который вы не нарисуете, покажет рабочий стол под ним. Следовательно, только ваши полигональные пиксели будут скрывать основной рабочий стол.

В результате окно рабочего стола никогда не нужно аннулировать или перекрашивать и т. д.

person MSalters    schedule 30.10.2012
comment
Это было дано как ответ раньше, но мне нужно щелкнуть по экрану одновременно с запуском программы. - person user1642826; 30.10.2012

Почему бы вам не использовать прозрачный 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
//

Реализация. Просто переместите окно, если хотите, чтобы анимация запускалась по всему рабочему столу.

#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;
}
person Lucian    schedule 30.10.2012
comment
Будет ли это позволять щелкать анимацию? - person user1642826; 30.10.2012
comment
Нет, насколько я знаю. Возможно, если вы используете PreTranslateMessage, чтобы он отправлял события нажатия клавиши и мыши через окно... - person Lucian; 30.10.2012
comment
Полный план, я знаю, что это не лучшая идея, но я хочу сделать настольного питомца. Так что вам нужно будет щелкнуть по нему, чтобы он не раздражал. - person user1642826; 30.10.2012
comment
пожалуйста, посмотрите на это: codeproject .com/Articles/12365/... извините, я прочитал статью, и в ней используются WTL и VS2005... Вероятно, это не применимо к вашему случаю. - person Lucian; 31.10.2012
comment
@user1642826: Звучит очень раздражающе, но если вы действительно хотите сделать это, лучшим способом было бы создать маленькое прозрачное окно, достаточно большое, чтобы показать вашего питомца, и перемещать это окно по мере его перемещения. Если вы нажмете на него, питомец уйдет, чтобы пользователь мог взаимодействовать с реальным рабочим столом внизу. (Если питомец не кошка, в этом случае правильным поведением будет отказ сдвинуться с места и не пропускать щелчки мышью. Вам нужен был этот ярлык? Не повезло.). - person hmakholm left over Monica; 31.10.2012