透明的儿童控制

时间:2009-10-24 00:41:25

标签: c++ windows windows-mobile user-controls

我正在编写一个可能使其某些部分透明或半透明的控件。基本上,此控件显示png图像(带alpha通道)。控件的父窗口上有一些图形。因此,要使png控件正确渲染,需要获取父窗口在其下方绘制的图像。父对话框可能设置了WS_CLIPCHILDREN标志,这意味着父窗口不会在png控件下绘制任何内容,在这种情况下,png控件将无法正常工作。 此控件也必须在Windows Mobile上运行,因此它不能具有WS_EX_TRANSPARENT

3 个答案:

答案 0 :(得分:0)

有趣的你应该问。我昨天写了代码来做这件事。它位于Project Resistance的代码库中。看看ResistorView(具有透明度的PNG)如何与MainForm(具有背景图像)进行交互。

答案 1 :(得分:0)

我没有做c#,所以我认为这不会有帮助。我试着查看你的代码,即使你完成了和我一样的任务,我也没有看到任何可以解决我问题的东西。 为了提供更多细节,我的控件还支持gif动画,我也使用了与你在项目中相同的IImage加载。根据我的经验,来自流的IImage加载是难以置信的垃圾代码,它非常慢。我不知道怎么可能这么慢。加载32x32 gif与31帧相似1.5secods使用垃圾IImage的东西。我编写了自己的加载器(使用一些开源gif库)并且没有任何优化gif帧的整个解码/加载花费不到100ms。我正在使用TouchPro2 ......我无法想象这段代码在低端设备上会有多糟糕。

作为一个快速替代方案,这是我的问题的可能解决方案:

在绘制图像(gif或png)的子控件的WM_PAINT处理程序中,我执行以下操作:

首先,我在self和父窗口上调用SetRedraw(false)。 然后我隐藏了子控件,并使用可选的HDC(作为wParam)将WM_PAINT发送到父窗口。父窗口将所有内容渲染到屏幕外位图(通过hdc传递到WM_PAINT),并在WM_PAINT成功返回后,我获取屏幕外位图的相关部分。 然后我启用show子窗口并在子窗口和父窗口上调用SetRedraw(true)。这个技巧有效,但显然有一些缺点(我需要创建一个巨大的屏幕外位图来捕获整个屏幕区域,即使我需要父窗口中间的32x32像素)。

代码如下:

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

答案 2 :(得分:0)

在WinCe中强制启用WS_CLIPCHILDREN,您无法切换它。我不知道为什么,也许这是出于性能原因。 根据我的经验,我在这种情况下做了什么。 1)如果父窗口bacgkround是动态的(例如包含可以移动的地图的窗口),则首先将其绘制到内存画布,然后绘制到屏幕,并保存内存画布并用于绘制透明子项。内存画布不包含代替子窗口的孔,因此它可用于进一步的像素合并。这里的缺点是将内存保存在内存中的内存消耗。

2)如果父窗口背景是静态的(对话框,菜单等),那么您可以创建非窗口子项。

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

您的父窗口将包含此类对象的数组,并重定向WM_PAINT和 鼠标点击它们。

disavantage是需要添加到父窗口的附加代码,但是您可以为所有父窗口创建一个基类,这将处理非窗口控件的问题。