Hi,
I'm trying to make a custom control to make a message balloon appear when a Cedit is focused. I know there are some classes on the internet but i'd really like to make one by myself. The problem i got is when i call the function Create(), there is no error, but nothing appear and onPaint is never called. If i use the resource editor, it works... Note that my main dialog is a dialog with a bitmap painted on it and have the shape of the bitmap.
myCtrl.cpp
Code:
// BalloonMessage.cpp : implementation file
//
#include "stdafx.h"
#include "TransparentDialog.h"
#include "BalloonMessage.h"
#define BALLONMESSAGE_CLASSNAME _T("MFCBalloonMessage")
// CBalloonMessage
IMPLEMENT_DYNAMIC(CBalloonMessage, CWnd)
CBalloonMessage::CBalloonMessage()
{
RegisterWindowClass();
}
CBalloonMessage::~CBalloonMessage()
{
}
BEGIN_MESSAGE_MAP(CBalloonMessage, CWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
// CBalloonMessage message handlers
void CBalloonMessage::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
dc.TextOut(0,0,"test");
}
BOOL CBalloonMessage::RegisterWindowClass(void)
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInst, BALLONMESSAGE_CLASSNAME, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = BALLONMESSAGE_CLASSNAME;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
BOOL CBalloonMessage::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
// TODO: Add your specialized code here and/or call the base class
return CWnd::Create(BALLONMESSAGE_CLASSNAME, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
void CBalloonMessage::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
CWnd::PreSubclassWindow();
}
void CBalloonMessage::PostNcDestroy()
{
// TODO: Add your specialized code here and/or call the base class
CWnd::PostNcDestroy();
}
CDialog::OnSize(nType, cx, cy);
// Load the image
m_hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), "palace.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (m_hBitmap == NULL)
{
MessageBox("Error loading bitmap");
return;
}
//Get information about the bitmap..
GetObject(m_hBitmap, sizeof(m_Bitmap), &m_Bitmap); // Get info about the bitmap
// Put the bitmap into a memory device context
CPaintDC dc(this);
//get a memory dc object
CDC dcMem;
//create a compatible dc
dcMem.CreateCompatibleDC(&dc); // Select the bitmap into the in-memory DC
//Select the bitmap into the dc
CBitmap* pOldBitmap = dcMem.SelectObject(CBitmap::FromHandle(m_hBitmap));
//Create a couple of region objects.
CRgn crRgn, crRgnTmp;
//create an empty region
crRgn.CreateRectRgn(0, 0, 0, 0);
//Create a region from a bitmap with transparency colour of Purple
COLORREF crTransparent = TRANSPARENTCOLOR;
int iX = 0;
int iY = 0;
for (iY = 0; iY < m_Bitmap.bmHeight; iY++)
{
do
{
//skip over transparent pixels at start of lines.
while (iX <= m_Bitmap.bmWidth && dcMem.GetPixel(iX, iY) == crTransparent)
iX++;
//remember this pixel
int iLeftX = iX;
//now find first non transparent pixel
while (iX <= m_Bitmap.bmWidth && dcMem.GetPixel(iX, iY) != crTransparent)
++iX;
//create a temp region on this info
crRgnTmp.CreateRectRgn(iLeftX, iY, iX, iY+1);
//combine into main region.
crRgn.CombineRgn(&crRgn, &crRgnTmp, RGN_OR);
//delete the temp region for next pass (otherwise you'll get an ASSERT)
crRgnTmp.DeleteObject();
}while(iX < m_Bitmap.bmWidth);
iX = 0;
}
//Centre it on current desktop
SetWindowRgn(crRgn, TRUE);
iX = (GetSystemMetrics(SM_CXSCREEN)) / 2 - (m_Bitmap.bmWidth / 2);
iY = (GetSystemMetrics(SM_CYSCREEN)) / 2 - (m_Bitmap.bmHeight / 2);
SetWindowPos(&wndTopMost, iX, iY, m_Bitmap.bmWidth, m_Bitmap.bmHeight, NULL);
// Free resources.
dcMem.SelectObject(pOldBitmap); // Put the original bitmap back (prevents memory leaks)
dcMem.DeleteDC();
crRgn.DeleteObject();
here's a project that i use to test my controll.
Note that for the moment the only this it should do is print some texe to the screen.
Thanks in advance
The problem with code is nothing but the fact that you created a local 'CBalloonMessage' object which would get destroyed when control went out of scope. So simply create an object in the heap by using new operator on 'CBalloonMessage' object.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.