C++ 如何制作缩小位图的动画并摆脱“;阴影&x201D;在OnEraseBkgnd()中使用StretchBlt围绕它?(MFC)

C++ 如何制作缩小位图的动画并摆脱“;阴影&x201D;在OnEraseBkgnd()中使用StretchBlt围绕它?(MFC),c++,mfc,C++,Mfc,我想在OnEraseBkgnd()中使用StretchBlt制作缩小位图的动画 这是我的密码: BOOL CMainDlg::OnEraseBkgnd(CDC* pDC) { double rat = 1; //ratio double width, height, x, y, time=0; CBitmap Background; BITMAP bm; CDC dcMemory; Background.LoadBitmap(IDB_CO

我想在
OnEraseBkgnd()
中使用
StretchBlt
制作缩小位图的动画

这是我的密码:

BOOL CMainDlg::OnEraseBkgnd(CDC* pDC)
{
    double rat = 1;     //ratio
    double width, height, x, y, time=0;
    CBitmap Background;
    BITMAP bm;
    CDC dcMemory;

    Background.LoadBitmap(IDB_COVER);   //Load Bitmap
    Background.GetBitmap(&bm);      //Load Bitmap into handle

    dcMemory.CreateCompatibleDC(pDC);
    dcMemory.SelectObject(&Background);

    pDC->SetStretchBltMode(HALFTONE);

    while(time <= 300){
        width = 800 * rat;
        height = 600 * rat;
        x = (800 - width) / 2;
        y = (600 - height) / 2;
        pDC->StretchBlt((int)x, (int)y, (int)width, (int)height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
        rat = easeOutExpo(time,1,-0.5,300);
        time+=5;
        Sleep(5);   //Delay 5 millisecond
    }

    return TRUE;
}

double CMainDlg::easeOutExpo(double e,double t,double u,double a){
    return (e==a)?t+u:u*(-pow(2,-10*e/a)+1)+t;
}
EDIT2:


我忘了说,
IDD_load
的对话框边框是NONE

代码正在原始图像上绘制越来越小的图像。每次都必须重新绘制背景,然后绘制新的较小图像。例如:

pDC->FillSolidRect(&rect, GetSysColor(COLOR_3DFACE));
pDC->StretchBlt(x, y, width, height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
但是,必须使用双缓冲来避免闪烁

首先,创建一个与前面创建的类似的内存dc(
buffer\u dc
)和一个内存位图(
buffer\u bitmap

在每个过程中,使用
FillSolidRect
填充
buffer\u dc
的背景。在
缓冲区\u dc
上绘制图像。最后,
BitBlt
所有内容到
pDC

BOOL CMainDlg::OnEraseBkgnd(CDC* pDC)
{
    CRect rect;
    GetClientRect(&rect);
    CDC buffer_dc;
    buffer_dc.CreateCompatibleDC(pDC);
    CBitmap buffer_bitmap;
    buffer_bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    CBitmap *buffer_oldbmp = buffer_dc.SelectObject(&buffer_bitmap);

    ...
    while(time <= 300)
    {
        ...
        buffer_dc.FillSolidRect(&rect, GetSysColor(COLOR_3DFACE));
        buffer_dc.StretchBlt((int)x, (int)y, (int)width, (int)height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
        pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &buffer_dc, 0, 0, SRCCOPY);

        Sleep(5);   
        ...
    }

    buffer_dc.SelectObject(buffer_oldbmp);
    return TRUE;
}

谢谢但我在位图下有另一个背景图像。这意味着我不能使用
FillSolidRect
来填充“阴影”。那么,有什么方法可以调用OnEraseBkgnd()?或者用其他方法来解决这个问题?顺便说一下,闪烁问题仍然存在。我不知道问题出在哪里…你在哪里画背景图像?显示
OnPaint
OnEraseBkgnd
中的所有绘画代码……实际上,我所说的不是“真实的”背景图像。我只是想说背景不是单色的。我最初的想法是直接在“屏幕”上显示位图。(不在对话框上)因此“背景(对话框外)”不是纯色。有关如何处理
无效
,请参阅编辑。对话框可以使自身失效,但它不能像您在另一个主题中尝试的那样,从
OnInitDialog
执行该操作。
BOOL CMainDlg::OnEraseBkgnd(CDC* pDC)
{
    CRect rect;
    GetClientRect(&rect);
    CDC buffer_dc;
    buffer_dc.CreateCompatibleDC(pDC);
    CBitmap buffer_bitmap;
    buffer_bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
    CBitmap *buffer_oldbmp = buffer_dc.SelectObject(&buffer_bitmap);

    ...
    while(time <= 300)
    {
        ...
        buffer_dc.FillSolidRect(&rect, GetSysColor(COLOR_3DFACE));
        buffer_dc.StretchBlt((int)x, (int)y, (int)width, (int)height, &dcMemory, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
        pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &buffer_dc, 0, 0, SRCCOPY);

        Sleep(5);   
        ...
    }

    buffer_dc.SelectObject(buffer_oldbmp);
    return TRUE;
}
class CSpashDlg : public CDialog
{
public:
    CSpashDlg(CWnd *wnd = NULL):CDialog(IDD_SPLASH, wnd){}
private:
    CBitmap m_bitmap;
    int m_width, m_height;
    BOOL OnInitDialog()
    {
        CDialog::OnInitDialog();

        HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"test.bmp",
            IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        if(!hbitmap)
        {
            AfxMessageBox(L"bitmap file not found\n");
            return TRUE;
        }

        m_bitmap.Attach(hbitmap);
        BITMAP bm;
        m_bitmap.GetBitmap(&bm);
        m_width = bm.bmWidth;
        m_height = bm.bmHeight;

        SetWindowPos(0, 100, 100, m_width, m_height, SWP_NOREDRAW);

        SetTimer(1, 1, 0);

        return TRUE;
    }

    void OnTimer(UINT_PTR timer)
    {
        if(timer != 1)
            return;
        CRect rc;
        GetWindowRect(&rc);
        if(rc.Width() < 10 || rc.Height() < 10)
        {
            KillTimer(1);
            PostMessage(WM_COMMAND, IDCANCEL);
            return;
        }

        rc.InflateRect(-1, -1);
        SetWindowPos(0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOREDRAW);
        Invalidate(FALSE);
    }

    void OnPaint()
    {
        CPaintDC dc(this);
        CRect rc;
        GetClientRect(&rc);

        CDC memdc;
        memdc.CreateCompatibleDC(0);
        memdc.SelectObject(&m_bitmap);

        dc.SetStretchBltMode(COLORONCOLOR);
        dc.StretchBlt(0, 0, rc.Width(), rc.Height(), 
            &memdc, 0, 0, m_width, m_height, SRCCOPY);
    }

    BOOL OnEraseBkgnd(CDC*)
    {
        return TRUE;
    }

    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CSpashDlg, CDialog)
    ON_WM_PAINT()
    ON_WM_ERASEBKGND()
    ON_WM_TIMER()
END_MESSAGE_MAP()

class MyApp : public CWinApp
{
public:
    BOOL InitInstance()
    {
        CWinApp::InitInstance();

        CSpashDlg splash;
        splash.DoModal();

        CDialog dlg(IDD_DIALOG1);
        dlg.DoModal();
        return FALSE;
    }
} a_app;