Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

TypeStatic - Utility for Saving Text

5.00/5 (4 votes)
21 Mar 2022CPOL1 min read 5.6K   118  
How to type text into a static control, change the font used and then save it into a bitmap
This tip shows how to enter text into a static control, change the font style, then save the static control in a Windows Bitmap.

Image 1

Introduction

I wanted a way to enter text into a Static Control and be able to change the font style, then save the Static Control in a Windows Bitmap.

The framework in a CDialog App handles the Space key the same way it does the Enter key and Escape key, It ends the dialog. Also, the framework does not send a WM_CHAR message in a dialog so I had to use PreTranslateMessage function to handle keyboard characters being typed. One other problem solved, using SetFont(&lf) for example, does not change the font size.

The Article Body

I did not want to "reinvent the wheel", so I used classes I found here on Code Project. The classes used are AutoFont and Drawing2Bitmap.

Using the Code

To initialize the bitmap and the font In OnInitDialog(), here, usually you could use m_autofont.SetFont(&lf) but a dialog won't let you change the font size that way.

C++
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = 160;
_tcsncpy_s(lf.lfFaceName, LF_FACESIZE, _T("Consolas"), 9);
m_autofont.CreatePointFontIndirect(&lf);

//Get the static window and create a corresponding bitmap with the same dimensions
StaticWnd.GetClientRect(&m_rcStaticWnd);
CDC* pDC = GetDC();
if(pDC != NULL)
{
    BMIH.biSize = sizeof(BITMAPINFOHEADER);
    BMIH.biBitCount = 24;
    BMIH.biPlanes = 1;
    BMIH.biCompression = BI_RGB;
    BMIH.biWidth = m_rcStaticWnd.Width();
    BMIH.biHeight = m_rcStaticWnd.Height();
    BMIH.biSizeImage = ((((BMIH.biWidth * BMIH.biBitCount) + 31) & ~31) >> 3) *
                                                                     BMIH.biHeight;
    m_hbStaticWnd = CreateDIBSection(pDC->GetSafeHdc(),
    (CONST BITMAPINFO*)&BMIH, DIB_RGB_COLORS, (void**)&m_pbStaticWndBits, NULL, 0);
    ReleaseDC(pDC);
}
/////////////////////////////////////////////////////////////////////////////////////
if((m_hbStaticWnd == NULL) || (m_pbStaticWndBits == NULL))
{
    //We could not create the bitmap, hide the Save Button
    AfxMessageBox(_T("BITMAP_NOT_CREATED_ERROR_MESSAGE"), MB_OK | MB_ICONSTOP);
    CWnd *pWnd;
    pWnd = GetDlgItem(IDC_SAVE_BITMAP);
    pWnd->ShowWindow(SW_HIDE);
}

The PreTranslateMessage() function to prevent the framework from closing the Dialog you need to return TRUE.

C++
BOOL CTypeStaticDlg::PreTranslateMessage(MSG* pMsg)
{
	// Check for backspace, delete and space key
	if(pMsg->message == WM_KEYDOWN)
	{
		if(pMsg->wParam == VK_BACK)
		{
			OnBackspace();
			return TRUE;
		}

		if(pMsg->wParam == VK_SPACE)
		{
			m_szLine += _T(" ");
			return TRUE;
		}
		if(pMsg->wParam == VK_DELETE)
		{
			m_szLine = _T("");
			GetCharTyped(0x00);
			return TRUE;
		}
	}
	//check for all other printable keys
	if(pMsg->message == WM_CHAR)
	{
		if(pMsg != NULL)
		{
			int key = pMsg->wParam;
			if(key > 32 && key < 127)
			{
				GetCharTyped(key);
			}
		}
	}
	return FALSE;

	return CDialogEx::PreTranslateMessage(pMsg);
}

This is the function that enters the text into the static control.

Here, you can set the font size.

C++
void CTypeStaticDlg::GetCharTyped(int key)
{
	char code;
	code = key;
	m_szLine += code;
	CFont *oldFont;
	CRect rc;
	CDC *pDC;
	pDC = StaticWnd.GetDC();
	oldFont = pDC->SelectObject(&m_autofont);
	pDC->SetTextColor(m_color);
	StaticWnd.GetClientRect(&rc);
	pDC->FillSolidRect(&rc, RGB(135, 206, 250));
	pDC->DrawText(m_szLine, &rc, DT_LEFT | DT_WORDBREAK);
	pDC->SelectObject(&oldFont);
	ReleaseDC(pDC);
}

Next, set the font for the static control.

If you want a different font, change its size, or color.

C++
void CTypeStaticDlg::OnBnClickedSetFont()
{
	m_autofont.GetFontFromDialog();
	CString szFont;
	szFont = m_autofont.ContractFont();
	m_autofont.ExtractFont(szFont);
	m_color = m_autofont.GetFontColor();
	StaticWnd.SetFont(&m_autofont);
	GetCharTyped(VK_UP);
}

This function prepares the image to be written into the bitmap.

C++
void CTypeStaticDlg::Draw()
{
	CDC* pDC = GetDC();
	if(pDC != NULL)
	{
		CDC dcMem;
		//Create a memory dc and select the drawing surface into it
		if(dcMem.CreateCompatibleDC(pDC) == TRUE)
		{
			HBITMAP hOldBitmap = (HBITMAP)SelectObject(dcMem.GetSafeHdc(), m_hbStaticWnd);	
			//////////////////////////////////////////////////////////////////////////////////
			//Once the static window has been selected into the memory dc, 
            //we can draw anything 
			//and have it all nicely collected in our bitmap for future use
			//Fill up the background, draw text
			CFont *oldFont;
			dcMem.FillSolidRect(0, 0, m_rcStaticWnd.Width(), 
                                m_rcStaticWnd.Height(), RGB(135, 206, 250));
			oldFont = dcMem.SelectObject(&m_autofont);
			dcMem.SetTextColor(m_color);
			dcMem.DrawText(m_szLine, &m_rcStaticWnd, DT_LEFT | DT_WORDBREAK);
			dcMem.SelectObject(&oldFont);
			//Now blit our memory drawing to the static control's rectangle
			BOOL bResult = BitBlt(pDC->GetSafeHdc(), 
								  m_rcStaticWnd.left,
								  m_rcStaticWnd.top,
								  m_rcStaticWnd.Width(),
								  m_rcStaticWnd.Height(),
								  dcMem.GetSafeHdc(),
								  0,
								  0,
								  SRCCOPY);
			//And deselect the static control's bitmap
			SelectObject(dcMem.GetSafeHdc(), hOldBitmap);
			//////////////////////////////////////////////////////////////////////////////////
		}
		ReleaseDC(pDC);
	}
}

Now when the user clicks the Save button, we write the bitmap data into the bitmap.

C++
void CTypeStaticDlg::OnBnClickedSaveBitmap()
{
	// TODO: Add your control notification handler code here
	Draw();
	CString szFilter;
	szFilter = _T("Windows Bitmap Files 
               (*.bmp)|*.bmp|Device Independant Bitmap(*.dib)|*.dib||");
	//Display the "Save As" dialog for the user to specify a path name
	CFileDialog dlg(FALSE, DEFAULT_BITMAP_FILE_EXTENSION, DEFAULT_BITMAP_FILE_NAME, 
	                OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, NULL);
	if(dlg.DoModal() == IDOK)
	{
		CString szPathName = dlg.GetPathName();
		//Create a new file for writing
		errno_t err;
		FILE *pFile;
		err = fopen_s(&pFile, szPathName, "wb");
		if(pFile == NULL)
		{
			AfxMessageBox(_T("FILE_CREATE_ERROR_MESSAGE"));
			return;
		}
		BITMAPFILEHEADER bmfh;	
		int nBitsOffset = sizeof(BITMAPFILEHEADER) + BMIH.biSize; 
		LONG lImageSize = BMIH.biSizeImage;
		LONG lFileSize = nBitsOffset + lImageSize;
		bmfh.bfType = 'B'+('M'<<8);			
		bmfh.bfOffBits = nBitsOffset;		
		bmfh.bfSize = lFileSize;				
		bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
		//Write the bitmap file header
		UINT nWrittenFileHeaderSize = fwrite(&bmfh, 1, sizeof(BITMAPFILEHEADER), pFile);
		//And then the bitmap info header
		UINT nWrittenInfoHeaderSize = fwrite(&BMIH, 1, sizeof(BITMAPINFOHEADER), pFile);
		//Finally, write the image data itself -- the data represents our text
		UINT nWrittenDIBDataSize = fwrite(m_pbStaticWndBits, 1, lImageSize, pFile);
		fclose(pFile);		

		SetDlgItemText(IDC_STATIC_SAVE, _T("Saved"));
	}	
}

History

  • 21st March, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)