Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Мерцание при перемещении и изменении размеров окна

#cpp #winapi


Хочу написать свои контролы. Столкнулся со всем известной проблемой - мерцанием.
Облазил все овэрфлоуи, сайберфорумы, рсдны и т.д. 

В общем, основной ответ - Двойная Буферизация. Ещё проскакивают варианты с обработкой
WM_ERASEBKGND, для случая, когда мерцание происходит при перетаскивании окна. В общем,
либо я дурак, либо ... Вот код, мерцание происходит при изменении размеров экрана,
в связи с рисовкой прямоугольника перед кругом(НО Я ЖЕ ИСПОЛЬЗУЮ ДВОЙНУЮ БУФЕРИЗАЦИЮ).
При перетаскивании второго(розоватого) над первым, за ним остаётся след. 

#include
#include
using namespace std;
class su
{
public:
    HWND q;
    HWND w;
    HWND z;
};
mapgu;
su *ss[2000]={NULL};
su *sq;
LRESULT CALLBACK WNDpROC(HWND,UINT,WPARAM,LPARAM);
    int WINAPI WinMain(HINSTANCE H,HINSTANCE,LPSTR,int c)
{
    WNDCLASS ok;
    ss[0]=new su;
    ZeroMemory(&ok,sizeof(ok));
    ok.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    ok.lpfnWndProc=WNDpROC;
    ok.style=CS_VREDRAW|CS_HREDRAW;
    ok.hInstance=H;
    ok.lpszClassName=L"s";
    RegisterClass(&ok);
    HWND hwnd=CreateWindow(L"s",NULL,WS_OVERLAPPEDWINDOW,0,0,600,400,NULL,NULL,H,NULL);
    gu[hwnd]=0;
    ss[0]->q=hwnd;ss[0]->w=CreateWindow(L"s",NULL,WS_CHILD|WS_VISIBLE,0,0,500,180,hwnd,NULL,H,NULL);
    ss[0]->z=CreateWindow(L"s",NULL,WS_CHILD|WS_VISIBLE,0,200,100,100,hwnd,NULL,H,NULL);

    ShowWindow(hwnd,1);
    UpdateWindow(hwnd);

    MSG msg;
    while(GetMessage(&msg,NULL,0,0))
        DispatchMessage(&msg);
}

int i(400);
LRESULT CALLBACK WNDpROC(HWND hwnd,UINT m,WPARAM p,LPARAM l)
{
    RECT r;
    GetClientRect(hwnd,&r);
    //анимация нажатия, с ней кстати в никакого мерцания не происходит, хотя окно
перерисовуется каждую 1/1000 секунды
    if(m==WM_TIMER&&p==1)
    {
        static bool a=false;
        if(a)
        {
            i+=15;
            InvalidateRect(hwnd,NULL,FALSE);
            if(i>=r.right)
            {
                a=false;
                KillTimer(hwnd,1);
            }
        }
        else
        {
            i-=25;
            InvalidateRect(hwnd,NULL,FALSE);
            if(i<=0)
            {
                a=true;
                i=0;
                KillTimer(hwnd,1);
            }
        }
    }
    if(m==WM_NCHITTEST&&hwnd==ss[gu[hwnd]]->z)
    {
        HRESULT hr=DefWindowProc(hwnd,m,p,l);
        if(hr==HTCLIENT)
        hr=HTCAPTION;
        return hr;
    }
    if(m==WM_ERASEBKGND)
        return 0;
    if(m==WM_LBUTTONUP&&hwnd==ss[gu[hwnd]]->w)
    {
        //рисуем круг
        SetTimer(hwnd,1,1,NULL);
    }
    if(m==WM_PAINT)
    {
        PAINTSTRUCT ps;
        HDC hdc=BeginPaint(hwnd,&ps);
        HDC hdc2=CreateCompatibleDC(hdc);
        HBITMAP hb2=CreateCompatibleBitmap(hdc,r.right,r.bottom);
        BitBlt(hdc2,0,0,r.right,r.bottom,hdc,0,0,SRCCOPY);
        SelectObject(hdc2,hb2);
        //сначала рисуем фон
        Rectangle(hdc2,-2,-2,r.right+2,r.bottom+2);
        //если надо рисовать в больший прямоугольник то создаём синию кисть и перо
        HBRUSH hb=CreateSolidBrush(RGB(41,134,204));
        HPEN hp=CreatePen(PS_SOLID,1,RGB(41,134,204));
        SelectObject(hdc2,hp);
        SelectObject(hdc2,hb);
        //а если рисуем в малёнком квдрате то создаём соответствующие кисти и т.д.
        if(hwnd==ss[gu[hwnd]]->z)
        {
            hb=CreateSolidBrush(RGB(200,134,204));
            hp=CreatePen(PS_SOLID,1,RGB(200,134,204));
            SelectObject(hdc2,hp);
            SelectObject(hdc2,hb);
            Rectangle(hdc2,0,0,r.right,r.bottom);
        }
        //ну и рисуем круг в тот больший прямоугольник, если он прищёл в ВндПроц
        if(hwnd==ss[gu[hwnd]]->w)
        Ellipse(hdc2,r.right/2-i,r.bottom/2-i,r.right/2+i,r.bottom/2+i);
        DeleteObject(hb);
        //высвобождаем память, копируем в ашдиси
        BitBlt(hdc,0,0,r.right,r.bottom,hdc2,0,0,SRCCOPY);
        DeleteDC(hdc2);
        DeleteObject(hb2);
        EndPaint(hwnd,&ps);
    }
    else if(m==WM_DESTROY)
        PostQuitMessage(0);
    else
        return DefWindowProc(hwnd,m,p,l);
}

    


Ответы

Ответ 1



Ответ найден, не прошло и года. Спасибо пользователю =А=L=X= (gamedev.ru). Абсолютно 100%-но рабочий вариант, если вы: Используете двойную буферизацию. Обрабатываете WM_ERASEBKGND,(как в коде выше). Что нужно сделать: Только одно - при создании родительского окна указать стильWS_CLIPCHILDREN(есть ещё WS_CLIPSIBLINGS, но его не пробовал). Ореол полностью пропадает, также пропадает мерцание. Ещё раз благодарю =А=L=X= за ответ.

Комментариев нет:

Отправить комментарий