Click here to Skip to main content
15,886,772 members
Articles / Desktop Programming / MFC
Tip/Trick

TypeStatic - Utility for Saving Text

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
21 Mar 2022CPOL1 min read 5.2K   118   1   2
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)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionscreenshot Pin
Roger6522-Mar-22 6:46
Roger6522-Mar-22 6:46 
Praisescreenshots will be helpful Pin
Southmountain21-Mar-22 14:43
Southmountain21-Mar-22 14:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.