将位图设置为静态控件MFC时出现问题 [英] Problems setting bitmaps to Static Control MFC
问题描述
我目前正在尝试基于对话框的GUI,同时尝试对其进行自定义.我已经绘制了一些位图,我想将它们用作dlg中的按钮和徽标.
I'm currently fighting with a dialog based GUI, while trying to customize it. I have drawn some bitmaps which I would like to use as buttons and as logos in the dlg.
我编写了两个成员函数,一个用于将位图设置为CButton
s,另一个用于将位图设置为CStatic
s.实际上,当按按钮调用它们时,两者都可以正常工作.但是在对话框初始化期间,只有用于设置CButton
的成员函数可以正常工作.我的CStatic
正在以某种方式被覆盖.
I have written two member functions, one for setting bitmaps to CButton
s, and one for setting bitmaps to CStatic
s. Actually both are working, when calling them on button press. But only the member-function for setting the CButton
s works properly during the initialisation of the dialog. My CStatic
s are getting overwritten somehow.
在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);
}
CButton
和CStatic
控件被声明为CMyDlg
的成员.
CButton
and CStatic
controls are declared as member of CMyDlg
.
关于如何避免这种行为的任何想法?还是有更好的方法将位图放置在对话框中? (我尝试过CImage::BitBlt()
,它也以某种方式被覆盖了.)
Any ideas on how I can avoid this behaviour? Or is there even a better way to place bitmaps in a dialog? (I tried CImage::BitBlt()
which got also overwritten somehow.)
推荐答案
问题是所有权之一:SetBitmap
的调用返回后,单个位图实例具有2个所有者,CBitmap
对象以及CButton
/CStatic
1)控件.当CBitmap
对象超出范围时,它将破坏单个实例,使控件具有无效位图的句柄.
The issue is one of ownership: After the call to SetBitmap
returns, the single bitmap instance has 2 owners, the CBitmap
object as well as the CButton
/CStatic
1) control. When the CBitmap
object goes out of scope, it destroys the single instance, leaving the control with a handle to an invalid bitmap.
标准解决方案是通过调用 CImage :: Detach( ),然后将HBITMAP
传递给按钮或静态控件:
The standard solution is to explicitly pass ownership, by invoking CImage::Detach() before passing the HBITMAP
off to the button or static control:
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);
}
}
有关实现的一些注意事项:
A few notes on the implementation:
- 从
string
到wstring
的转换失败,除非 file 仅使用ASCII字符.我更改了代码以处理ANSI代码页编码,但这可能不是源编码.您可能需要更改它. 2) - 不需要从
CImage
到CBitmap
的转换.CImage
既有operator HBITMAP()
成员又有Detach()
成员,这就是我们在这里真正需要的全部内容. - 对
SetBitmap
的调用将返回先前关联的位图的句柄.我们负责清理.
- Your conversion from
string
towstring
fails unless file uses ASCII characters only. I changed the code to deal with ANSI codepage encoding, but that may not be the source encoding. You may have to change this.2) - The conversion from
CImage
toCBitmap
is not needed.CImage
has both anoperator HBITMAP()
as well as aDetach()
member, and that's all we really need here. - The call to
SetBitmap
returns a handle to the previously associated bitmap. We are responsible for cleanup.
1) 没有书面合同,按钮和静态控件的行为不同.如果它似乎适用于按钮,则仅出于巧合.这不是您应该依靠的任何东西.建议对按钮和静态控件使用相同的解决方案.
2) Windows始终使用UTF-16.通常最好也将UTF-16用作应用程序的内部字符编码.建议使用std::wstring
.
这篇关于将位图设置为静态控件MFC时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!