views:

197

answers:

3

Hello all, I'm writing a control that may have some of its parts transparent or semitransparent. Basically this control shows a png image (with alpha channel). The control's parent window has some graphics on it. Therefore, to make the png control render correctly it needs to get image of what the parent window would draw beneath it. Parent dialog might have WS_CLIPCHILDREN flag set, that means that the the parent window won't draw anything under the the png control and in this case png control won't work properly. This control has to work on Windows Mobile also, so it can't have WS_EX_TRANSPARENT

A: 

Funny you should ask. I just wrote code to do this yesterday. It's in the code base for Project Resistance. Look at how ResistorView (which has a PNG with transparency) interacts with MainForm (which has the background image).

ctacke
A: 

I'm not doing c#, so I don't think that could be helpful. I tried to look into your code and I don't see anything that can solve my problem even though you accomplish the same task as me. To give more details, my control also supports gif animation and I also used the same IImage load from stream as you do in your project. From my experience, that IImage load from stream is unbelievable junk code, it's extremely slow. I have no idea how that possibly could be so slow. Loading 32x32 gif with 31 frames takes like 1.5secods using that junk IImage stuff. I wrote my own loader (using some opensource gif library) and without any optimization entire decoding/loading of the gif frames takes less than 100ms. I'm using TouchPro2... I can't imagine how badly this code would perform on a low end device.

As a quick alternative here's a possible solution to my question:

in the WM_PAINT handler of the child control that draws images (gif or png) I do the following:

first, I call SetRedraw(false) on self and on parent window. then I hide the child control, and send WM_PAINT to parent window with optional HDC (as wParam). The parent window renders everything to the offscreen bitmap (passed via hdc to WM_PAINT) and after WM_PAINT successfully returns I take relevant part of the offscreen bitmap. Then I enable show the child window and call SetRedraw(true) on both child and the parent window. That trick works but has some disadvantages obviously (I need to createa huge offscreen bitmap to capture entire screen area even though I need 32x32 pixel from the middle of parent window).

the code is below:

bool pic_control::get_parent_bg(MyBitmap & bg)
{
    CWindow parent = GetParent();
    CClientDC dc(parent);
    bool is_visible = IsWindowVisible() && parent.IsWindowVisible();
    if(!is_visible){
     return false;
    }

    parent.SetRedraw(false);
    SetRedraw(false);

    CRect rect;
    parent.GetClientRect(rect);
    MyBitmap bmp;
    bmp.create(rect.Width(), rect.Height());

    ShowWindow(SW_HIDE);
    parent.SendMessage(WM_PAINT, (WPARAM)(HDC)bmp.dc());
    ShowWindow(SW_SHOW);

    GetWindowRect(rect);
    parent.ScreenToClient(rect);
    bg.create(rect.Width(), rect.Height());
    bg.dc().BitBlt(0, 0, rect.Width(), rect.Height(), bmp.dc(), rect.left, rect.top, SRCCOPY);

    IF_DEBUG SAL::saveHBITMAPToJpeg(bg.GetBitmap(), "frames/BG.jpg", 100);

    SetRedraw(true);
    parent.SetRedraw(true);
    return true;
}
pps
A: 

WS_CLIPCHILDREN is forced on in WinCe, you cannot toggle it. I dont know why, maybe it is done for performance reasons. From my experience what i did in this situation. 1) If the parent window bacgkround is dynamic (for instance window that contains map, which can be moved), then it is painted to memory canvas first, then to the screen, and memory canvas is saved and used for painting transparent childs. Memory canvas would not contain holes in place of child windows, so it can be used for futher pixel merge. The disadvantage here is memory consumption to hold canvas in memory.

2) If parent window background is static (dialog box, menu, etc) then you can make non-window childs.

class CImageButton
{
public:
bool IsPointInside(POINT pt);
void OnPaint(HDC canvas);
void OnClick();
void SetRect(RECT& rc);
private:
RECT m_rc;
};

Your parent window will contain an array of such objects and redirect WM_PAINT and mouse clicks to them.

The disavantage is additional code needed to be added to parent window, but you can make a base class for all your parent windows, which would handle issues with non-windowed controls.

southerton