2011-03-07 5 views
2

Конечной целью этого является наличие заставки в окнах с прозрачностью, но это не то, что я застрял прямо сейчас.Экран всплеска Windows с использованием GDI +

Чтобы создать прозрачное окно, я сначала пытаюсь объединить заставку и текст в буфер вне экрана с помощью GDI +.

В настоящее время я просто пытаюсь создать буфер и отобразить его в ответ на сообщение «WM_PAINT». На данный момент это не работает; все, что я вижу, это черное окно.

Я полагаю, я понял кое-что касаемо установки целей визуализации в GDI +, а затем делает их (я пытаюсь сделать экран, используя прямой GDI Blit)

Во всяком случае, вот код до сих пор :

//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     
} 

И вот snipit, который обрабатывает сообщение WM_PAINT:

---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 + с помощью GDI-до сих пор стоит. – Luther

+1

Этот код не будет работать, поскольку сообщения WM_PAINT НЕ отправляются, если в этом окне добавлен стиль WS_EX_LAYERED. Это приводит к тому, что окна только расширяют свою копию оконного растрового изображения Windows, обновляемого UpdateLayeredWindow. –

+0

Спасибо за подсказку Крис. Сейчас я отключил многоуровневый флаг, но у меня все еще не получается рисовать альфа-смешанное изображение. В настоящее время я пытаюсь использовать «AlphaBlend», который, кажется, является заменой fpr BitBlt для рендеринга альфа-смешанных изображений. Пока нет кубиков, он просто устанавливает GetLastError в «ERROR_INVALID_PARAMETER», но не уточняет. Я никогда не буду дружить с Win32 и GDI; они просто не играют хорошо! Альфа-смешивание должно быть тривиальным. – Luther

ответ

2

Решил, хотя я уверен, что это не оптимально. Во-первых, как предложил Крис Бекке, вы не должны отвечать на сообщение WM_PAINT и должны обновляться только с помощью «UpdateLayeredWindow». Одна из проблем, которые у меня были, это то, что дал UpdateLayeredWindow некоторые плохие координаты, в частности, я заменил источник и назначение вокруг (doh!)

Вот код для вызова UpdateLayeredWindow с поверхности GDI +. Это не оптимально, но оно работает.

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

Смежные вопросы