2011-03-07 65 views
2

最终的目标是在使用透明度的窗口中有一个启动画面,但这不是我现在卡住的内容。使用GDI的Windows启动画面+

为了创建一个透明窗口,我首先尝试使用GDI +将闪屏和文本组合到屏幕外的缓冲区中。

目前,我只是想组合缓冲区并显示它以响应'WM_PAINT'消息。目前这还没有解决。我看到的只是一个黑色的窗口。

我想我误解的东西有关于设置渲染GDI +目标,然后使它们(我试图用简单的GDI位图传送到渲染屏幕)

总之,这里的代码,使远:

//my window initialisation code 
void MyWindow::create_hwnd(HINSTANCE instance, const SIZE &dim) 
{      
    DWORD ex_style = WS_EX_LAYERED ; //eventually I'll be making use of this layerd flag 
    m_hwnd = CreateWindowEx(
      ex_style, 
      szFloatingWindowClass , 
      L"", 
      WS_POPUP , 
      0, 
      0,  
      dim.cx, 
      dim.cy, 
      null, 
      null, 
      instance, 
      null);  


     m_display_dc = GetDC(NULL); 
     //This was sanity check test code - just loading a standard HBITMAP and displaying it in WM_PAINT. It worked fine 
     //HANDLE handle= LoadImage(NULL , L"c:\\test_image2.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);  
     m_gdip_offscreen_bm = new Gdiplus::Bitmap(dim.cx, dim.cy); 

     m_gdi_dc = Gdiplus::Graphics::FromImage(m_gdip_offscreen_bm);//new Gdiplus::Graphics(m_splash_dc);//window_dc ;m_splash_dc  

     //this draws the conents of my splash screen - this works if I create a GDI+ context for the window, rather than for an offscreen bitmap. 
     //For all I know, it might actually be working but when I try to display the contents on screen, it shows a black image 
     draw_all(); 
     //this is just to show that drawing something simple on the offscreen bit map seems to have no effect 
     Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255)); 
     m_gdi_dc->DrawLine(&pen, 0,0,100,100); 

     DWORD last_error = GetLastError(); //returns '0' at this stage     
} 

及这里的处理WM_PAINT消息snipit:

---8<----------------------- 
//Paint message snippit 

    case WM_PAINT: 
    { 
     BITMAP bm; 
     PAINTSTRUCT ps; 

     HDC hdc = BeginPaint(vg->m_hwnd, &ps); //get the HWNDs DC 

     HDC hdcMem = vg->m_gdi_dc->GetHDC(); //get the HDC from our offscreen GDI+ object 

     unsigned int width = vg->m_gdip_offscreen_bm->GetWidth(); //width and height seem fine at this point 
     unsigned int height = vg->m_gdip_offscreen_bm->GetHeight(); 
     BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY); //this blits a black rectangle 

     DWORD last_error = GetLastError();    //this was '0' 

     vg->m_gdi_dc->ReleaseHDC(hdcMem); 

     EndPaint(vg->m_hwnd, &ps); //end paint 

     return 1; 
    } 

    ---8<----------------------- 

我对长期职位的歉意。有人知道我不怎么了解你如何使用GDI +(或GDI)写入屏幕外缓冲区,然后将其显示在屏幕上?

谢谢您的阅读。

+0

我发现如果我为屏幕创建另一个GDI +上下文并使用它绘制合成的上下文,它可以正常工作。但是,我试图使用GDI-方法的原因是为了能够使用' UpdateLayeredWindow”。我的问题,如何使用GDI blit GDI +图像仍然站立。 – Luther 2011-03-07 16:33:42

+1

如果窗口具有以这种方式添加的WS_EX_LAYERED样式,则不会发送此代码,因为不会发送WM_PAINT消息。这会导致窗口只触发UpdateLayeredWindow更新的窗口离屏位图副本。 – 2011-03-08 08:01:16

+0

感谢您的提示克里斯。我暂时关闭分层标志,但仍然无法绘制alpha混合图像。我目前正在尝试使用'AlphaBlend',它似乎是用于渲染alpha混合图像的替代fpr BitBlt。目前为止没有骰子,它只是将GetLastError设置为'ERROR_INVALID_PARAMETER',但没有详细说明。我永远不会与Win32和GDI成为朋友;他们只是玩不好!阿尔法混合应该是微不足道的。 – Luther 2011-03-08 10:37:16

回答

2

解决了它,虽然我确定这不是最佳。首先,正如Chris Becke所建议的那样,您不应该回应WM_PAINT消息,而应该只使用'UpdateLayeredWindow'进行更新。其中一个我是给UpdateLayeredWindow一些不好的坐标中的问题,特别是我已经换了源和目的地周围(DOH!)

下面的代码从一个GDI +表面调用UpdateLayeredWindow。这不是最优的,但它的工作原理。

void TOPLEVEL_FLOATING_WINDOW::update_layered_window() 
{ 
    BLENDFUNCTION blend_func = { 0 };  //build the blend function object... I guess microsoft doesn't/didn't like constructors 
    blend_func.AlphaFormat = AC_SRC_OVER; 
    blend_func.BlendFlags = 0; 
    blend_func.SourceConstantAlpha = 255; 
    blend_func.AlphaFormat = AC_SRC_ALPHA; 

    POINT_2i pt = m_screen_pos; 
    VECTOR_2i dim = m_bounds.dimensions(); 

    POINT_2i pt_src (0,0) ;    

    Gdiplus::Color bg(0,0,0,0); 
    m_gdip_offscreen_bm->GetHBITMAP(bg, &m_offscreen_bm); //get the Hbitmap from my GDI+ bitmap - I think this is allocating a whole new bitmap off the heap. Yuck, very inefficient! 
    HDC splash_dc = CreateCompatibleDC(m_display_dc);  //create a temporary HDC   
    HGDIOBJ oldobj = SelectObject(splash_dc , m_offscreen_bm); //'select' the bitmap.  
    UpdateLayeredWindow(m_hwnd,m_display_dc, (POINT*)&pt, (SIZE*)&dim, splash_dc , (POINT*)&pt_src, 0 ,&blend_func,ULW_ALPHA); //this call works and updates our splash screens hidden buffer  
    SelectObject(splash_dc, oldobj); //some tidy up code 
    DeleteObject(m_offscreen_bm);  //free the bitmap. Memory fragmentation HO! 
    DeleteDC(splash_dc); //Delete the DC   
} 

这里就是我认为应该工作,但没有。我会向任何可以告诉我为什么不告诉我的人发表一些看法!我想这是因为HDC不是天生平等的,并且UpdateLayeredWindow函数只能以某种方式接受由特定源创建的HDC。如果这个规则更明显,那将会很好。

void TOPLEVEL_FLOATING_WINDOW::update_layered_window_in_an_ideal_world() 
    { 
     m_refresh_needed = false; 
     BLENDFUNCTION blend_func = { 0 }; 
     blend_func.AlphaFormat = AC_SRC_OVER; 
     blend_func.BlendFlags = 0; 
     blend_func.SourceConstantAlpha = 255; 
     blend_func.AlphaFormat = AC_SRC_ALPHA; 

     POINT_2i pt = m_screen_pos; 
     VECTOR_2i dim = m_bounds.dimensions(); 

     POINT_2i pt_src (0,0) ;    

     HDC gdi_HDC = m_screen_gdi_dc->GetHDC(); //I have a GDI+ 'Graphics' object whose back buffer is the image I want to composite on to the desktop  
     UpdateLayeredWindow(m_hwnd,m_display_dc, (POINT*)&pt, (SIZE*)&dim, gdi_HDC , (POINT*)&pt_src, 0 ,&blend_func,ULW_ALPHA); 
     m_screen_gdi_dc->ReleaseHDC(gdi_HDC); //be nice and release the gdi_HDC 
    } 

唯一的另一种方法是忽略GDI +,并用自己的光栅库,这是很乐意渲染到屏幕外的任何缓冲呈现的一切。但是,这对于这个项目来说太过分了。

2

以下是将GDI +位图获取到分层窗口的方法。这允许多个位图叠加,定位和重新调整大小。

void SetSplashImage() 
{ 
    // Default to upper left of screen 
    POINT ptOrigin = { 0, 0 }; 
    SIZE sizeSplash = { 128, 128 }; 

    // Get the actual screen location 
    GetPointOfOrigin(ptOrigin, sizeSplash); 

    // Our in memory database of GDI+ Bitmaps 
    data::image::BoxOfBits *box = 
    dynamic_cast<data::image::BoxOfBits *>(&Images.get_package("skin_layout_008")); 

    // Create a display context as a canvas to draw the images 
    HDC hdcScreen = GetDC(NULL); 
    HDC hdcMem = CreateCompatibleDC(hdcScreen); 
    HBITMAP bmMem = CreateCompatibleBitmap(hdcScreen, sizeSplash.cx, sizeSplash.cy); 

    // Prep canvas for rendering graphic 
    HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, bmMem); 
    Gdiplus::Graphics graphics(hdcMem); 

    // Base image is a pic of a folder 
    Gdiplus::RectF canvasDest(0,0,128,128); 
    graphics.DrawImage(box->grab("black_folder").pBitmap_, 
    canvasDest, 0,0,128,128, Gdiplus::UnitPixel); 

    // Overlay a pic of some tools in center of folder 
    Gdiplus::RectF canvasDest2(30,50,64,64); // resize half actual size 
    graphics.DrawImage(box->grab("work_tools").pBitmap_, 
    canvasDest2, 0,0,128,128, Gdiplus::UnitPixel); 

    // Overlay a pic of a cog in upper left corner of folder 
    Gdiplus::RectF canvasDest1(16,16,32,32); // resize half actual size 
    graphics.DrawImage(box->grab("cog_edit").pBitmap_, 
    canvasDest1, 0,0,32,32, Gdiplus::UnitPixel); 

    // Prepare to alpha blend the canvas with the screen 
    BLENDFUNCTION blend = { 0 }; 
    blend.BlendOp = AC_SRC_OVER; 
    blend.SourceConstantAlpha = 255; 
    blend.AlphaFormat = AC_SRC_ALPHA; 

    // Composite the canvas with the screen into the layered window 
    POINT ptZero = { 0 }; 
    UpdateLayeredWindow(hwnd_, hdcScreen, &ptOrigin, &sizeSplash, 
     hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA); 

    // Delete temporary objects used for canvas 
    SelectObject(hdcMem, hbmpOld); 
    DeleteObject(bmMem); 
    DeleteDC(hdcMem); 
    ReleaseDC(NULL, hdcScreen); 

    // Update mouse hit-test coordinates 
    GetWindowRect(hwnd_, &rcMousedown_); 
} 

三个位图组成的分层窗口看起来是这样的画面: - 猜我没有足够的声誉张贴的图片:(

这里的链接,但 - http://i.stack.imgur.com/HmU7H.png