将位图设置为静态控制MFC

时间:2016-06-06 09:47:15

标签: c++ visual-c++ bitmap mfc

我目前正在尝试使用基于对话框的GUI,同时尝试自定义它。我已经绘制了一些位图,我想用它作为按钮和dlg中的徽标。

我写了两个成员函数,一个用于将位图设置为CButton,另一个用于将位图设置为CStatic s。实际上,当按下按钮时,它们都正在工作。但是,在对话框初始化期间,只有用于设置CButton的成员函数才能正常工作。我的CStatic被某种方式覆盖了。

这在OnInitDialog()

中调用时有效
void CMyDlg::setBitmapAsButton(std::string file, CButton &Button, int xPos, int yPos)
{
    CImage imgFromFile;
    CBitmap bitmap;
    std::wstring wfile(file.begin(), file.end());

    HRESULT ret = imgFromFile.Load(wfile.c_str());
    int width = imgFromFile.GetWidth();
    int height = imgFromFile.GetHeight();
    bitmap.Attach(imgFromFile.Detach());

    Button.Create(_T("My button"), WS_CHILD | WS_VISIBLE | BS_BITMAP,
    CRect(xPos, yPos, xPos + width, yPos + height), this, 1);
    Button.SetBitmap(bitmap);
}

OnInitDialog()中调用时,这不起作用:

void CVisTrayDlg::setBitmapAsStatic(std::string file, CStatic &Static, int xPos, int yPos)
{
    CImage imgFromFile;
    CBitmap bitmap;
    std::wstring wfile(file.begin(), file.end());

    HRESULT ret = imgFromFile.Load(wfile.c_str());
    int width = imgFromFile.GetWidth();
    int height = imgFromFile.GetHeight();
    bitmap.Attach(imgFromFile.Detach());

    Static.Create(_T("My Static"), WS_CHILD | WS_VISIBLE | SS_BITMAP,
    CRect(xPos, yPos, xPos + width, yPos + height), this);
    Static.SetBitmap(bitmap);
}

CButtonCStatic控件被声明为CMyDlg的成员。

关于如何避免这种行为的任何想法?或者是否有更好的方法将位图放在对话框中? (我尝试了CImage::BitBlt(),但也以某种方式被覆盖了。)

2 个答案:

答案 0 :(得分:4)

问题是所有权问题:在调用SetBitmap后,单个位图实例有2个所有者,CBitmap对象以及CButton / {{1} } 1)控制。当CStatic对象超出范围时,它会销毁单个实例,使控件留下无效位图的句柄。

标准解决方案是通过在将CBitmap关闭到按钮或静态控件之前调用CImage::Detach()来明确传递所有权:

HBITMAP

关于实施的一些注释:

  • 除非 file 仅使用ASCII字符,否则从void CVisTrayDlg::setBitmapAsStatic(std::string file, CStatic &Static, int xPos, int yPos) { CImage bitmap; // Convert from ANSI codepage to UTF-16 CStringW wfile(file.c_str()); // Error handling needed. Use the SUCCEEDED() or FAILED() macros here: HRESULT ret = bitmap.Load(wfile); int width = bitmap.GetWidth(); int height = bitmap.GetHeight(); Static.Create(_T("My Static"), WS_CHILD | WS_VISIBLE | SS_BITMAP, CRect(xPos, yPos, xPos + width, yPos + height), this); // Pass ownership from CImage to CStatic: HBITMAP hbmOld = Static.SetBitmap(bitmap.Detach()); // SetBitmap() passes ownership of the previous image (if set). // We are responsible for cleanup: if (hbmOld != nullptr ) { ::DeleteObject(hbmOld); } } string的转换将失败。我更改了代码以处理ANSI代码页编码,但这可能不是源代码编码。您可能需要更改此内容。 2)
  • 不需要从wstring转换为CImageCBitmap同时拥有CImage成员和operator HBITMAP()成员,这就是我们真正需要的所有成员。
  • Detach()的调用返回先前关联的位图的句柄。我们负责清理工作。

<小时/> 1) 没有记录合同,按钮和静态控件的行为不同。如果它似乎适用于按钮,那么它只是巧合。这不是你应该依赖的任何东西。建议对按钮和静态控件使用相同的解决方案。

2) Windows始终使用UTF-16。通常最好使用UTF-16作为应用程序的内部字符编码。建议使用SetBitmap

答案 1 :(得分:2)

确保CBitmap对象保留在内存中。因此,make是您的类的成员变量。对话框类的析构函数最终将调用位图对象的析构函数,因此无需担心资源/内存泄漏。

对于按钮,当您移动/恢复窗口时,它可能会显示其效果。我建议你在按钮中保留CBitmap对象也在内存中。