前段时间,一个底层开发的同事写一个MFC工具,在想实现设置属性页字体时遇到了困难,问我该如何实现?根据多年的经验,想当然的以为很简单,只需在资源里,更改对话框的字体即可,试了试不行;那就CreateFont,然后SetFont,可是无论怎么弄,程序运行后,属性页的字体依然如故!在网上搜索也没有找到好的解决办法,最后折腾许久,终于找到一篇文章,最终把这个问题解决了。
文章:
http://support.microsoft.com/default.aspx?scid=kb;en-us;142170示例下载:
http://download.microsoft.com/download/vc60pro/samp40/1/win98/en-us/prpfont.exe
概要
PRPFONT 说明如何为您 CPropertyPages 在资源编辑器, 并在运行时设置所需字体, 设置要和一切正常大小相同表的字体。 所有这是一个类称为 CMySheet 中完成。 调用 ChangeDialogFont() 函数进行调整窗口以及设置字体工作。 CPropertySheet::BuildPropPageArray() 被覆盖以便不重置网页中字体。
更多信息
在 VisualC++ 的版本低于 4.0, MFC 必须自己实现 CPropertySheet。 对于您 CPropertySheet 通过资源编辑器中设置首 CPropertyPage 您对话框资源的字体可能设置字体。 在运行时, 表将使用字体设置并一切根据字体大小。 开头 VisualC++4.0, MFC 使用 Windows 95 PropertySheet 控件。 此控件将始终使用系统字体来表。 这是设计使然。 MFC 还将强制页以用作表相同字体。 这样调用 BuildPropPageArray() 函数中。 因为这是无出处函数, 它可能更改或将来的 MFC 版本中被删除。
CMySheet 将使用的首活动 CPropertyPage 字体来设置字体和 CPropertySheet 和其子窗口大小。 CPropertyPages 与资源编辑器中指定字体显示。
具体步骤:
1、新建类CMySheet,继承自CPropertySheet
2、在.cpp文件中大概实现如下。
3、修改.h文件。
4、使用这个CMySheet,更改资源中的属性页,则程序运行后,设置的字体有效。
#define WM_RESIZEPAGE WM_APP+1
enum { CDF_CENTER, CDF_TOPLEFT, CDF_NONE };
// helper function which sets the font for a window and all its children
// and also resizes everything according to the new font
void ChangeDialogFont(CWnd* pWnd, CFont* pFont, int nFlag)
{
CRect windowRect;
// grab old and new text metrics
TEXTMETRIC tmOld, tmNew;
CDC * pDC = pWnd->GetDC();
CFont * pSavedFont = pDC->SelectObject(pWnd->GetFont());
pDC->GetTextMetrics(&tmOld);
pDC->SelectObject(pFont);
pDC->GetTextMetrics(&tmNew);
pDC->SelectObject(pSavedFont);
pWnd->ReleaseDC(pDC);
long oldHeight = tmOld.tmHeight+tmOld.tmExternalLeading;
long newHeight = tmNew.tmHeight+tmNew.tmExternalLeading;
if (nFlag != CDF_NONE)
{
// calculate new dialog window rectangle
CRect clientRect, newClientRect, newWindowRect;
pWnd->GetWindowRect(windowRect);
pWnd->GetClientRect(clientRect);
long xDiff = windowRect.Width() - clientRect.Width();
long yDiff = windowRect.Height() - clientRect.Height();
newClientRect.left = newClientRect.top = 0;
newClientRect.right = clientRect.right * tmNew.tmAveCharWidth / tmOld.tmAveCharWidth;
newClientRect.bottom = clientRect.bottom * newHeight / oldHeight;
if (nFlag == CDF_TOPLEFT) // resize with origin at top/left of window
{
newWindowRect.left = windowRect.left;
newWindowRect.top = windowRect.top;
newWindowRect.right = windowRect.left + newClientRect.right + xDiff;
newWindowRect.bottom = windowRect.top + newClientRect.bottom + yDiff;
}
else if (nFlag == CDF_CENTER) // resize with origin at center of window
{
newWindowRect.left = windowRect.left -
(newClientRect.right - clientRect.right)/2;
newWindowRect.top = windowRect.top -
(newClientRect.bottom - clientRect.bottom)/2;
newWindowRect.right = newWindowRect.left + newClientRect.right + xDiff;
newWindowRect.bottom = newWindowRect.top + newClientRect.bottom + yDiff;
}
pWnd->MoveWindow(newWindowRect);
}
pWnd->SetFont(pFont);
// iterate through and move all child windows and change their font.
CWnd* pChildWnd = pWnd->GetWindow(GW_CHILD);
while (pChildWnd)
{
pChildWnd->SetFont(pFont);
pChildWnd->GetWindowRect(windowRect);
CString strClass;
::GetClassName(pChildWnd->m_hWnd, strClass.GetBufferSetLength(32), 31);
strClass.MakeUpper();
if(strClass==_T("COMBOBOX"))
{
CRect rect;
pChildWnd->SendMessage(CB_GETDROPPEDCONTROLRECT,0,(LPARAM) &rect);
windowRect.right = rect.right;
windowRect.bottom = rect.bottom;
}
pWnd->ScreenToClient(windowRect);
windowRect.left = windowRect.left * tmNew.tmAveCharWidth / tmOld.tmAveCharWidth;
windowRect.right = windowRect.right * tmNew.tmAveCharWidth / tmOld.tmAveCharWidth;
windowRect.top = windowRect.top * newHeight / oldHeight;
windowRect.bottom = windowRect.bottom * newHeight / oldHeight;
pChildWnd->MoveWindow(windowRect);
pChildWnd = pChildWnd->GetWindow(GW_HWNDNEXT);
}
}
/////////////////////////////////////////////////////////////////////////////
// CMySheet
IMPLEMENT_DYNAMIC(CMySheet, CPropertySheet)
CMySheet::CMySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
}
CMySheet::CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
:CPropertySheet(pszCaption, pParentWnd, iSelectPage)
{
}
CMySheet::~CMySheet()
{
if (m_fntPage.m_hObject)
VERIFY (m_fntPage.DeleteObject ());
}
BEGIN_MESSAGE_MAP(CMySheet, CPropertySheet)
//{{AFX_MSG_MAP(CMySheet)
//}}AFX_MSG_MAP
ON_MESSAGE (WM_RESIZEPAGE, OnResizePage)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMySheet message handlers
void CMySheet::BuildPropPageArray()
{
CPropertySheet::BuildPropPageArray();
// get first page
CPropertyPage* pPage = GetPage (0);
ASSERT (pPage);
// dialog template class in afxpriv.h
CDialogTemplate dlgtemp;
// load the dialog template
VERIFY (dlgtemp.Load (pPage->m_psp.pszTemplate));
// get the font information
CString strFace;
WORD wSize;
VERIFY (dlgtemp.GetFont (strFace, wSize));
if (m_fntPage.m_hObject)
VERIFY (m_fntPage.DeleteObject ());
// create a font using the info from first page
VERIFY (m_fntPage.CreatePointFont (wSize*10, strFace));
}
BOOL CMySheet::OnInitDialog()
{
CPropertySheet::OnInitDialog();
// get the font for the first active page
CPropertyPage* pPage = GetActivePage ();
ASSERT (pPage);
// change the font for the sheet
ChangeDialogFont (this, &m_fntPage, CDF_CENTER);
// change the font for each page
for (int iCntr = 0; iCntr < GetPageCount (); iCntr++)
{
VERIFY (SetActivePage (iCntr));
CPropertyPage* pPage = GetActivePage ();
ASSERT (pPage);
ChangeDialogFont (pPage, &m_fntPage, CDF_CENTER);
}
VERIFY (SetActivePage (pPage));
// set and save the size of the page
CTabCtrl* pTab = GetTabControl ();
ASSERT (pTab);
if (m_psh.dwFlags & PSH_WIZARD)
{
pTab->ShowWindow (SW_HIDE);
GetClientRect (&m_rctPage);
CWnd* pButton = GetDlgItem (ID_WIZBACK);
ASSERT (pButton);
CRect rc;
pButton->GetWindowRect (&rc);
ScreenToClient (&rc);
m_rctPage.bottom = rc.top-2;
}
else
{
pTab->GetWindowRect (&m_rctPage);
ScreenToClient (&m_rctPage);
pTab->AdjustRect (FALSE, &m_rctPage);
}
// resize the page
pPage->MoveWindow (&m_rctPage);
return TRUE;
}
BOOL CMySheet::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
NMHDR* pnmh = (LPNMHDR) lParam;
// the sheet resizes the page whenever it is activated so we need to size it correctly
if (TCN_SELCHANGE == pnmh->code)
PostMessage (WM_RESIZEPAGE);
return CPropertySheet::OnNotify(wParam, lParam, pResult);
}
LONG CMySheet::OnResizePage (UINT, LONG)
{
// resize the page
CPropertyPage* pPage = GetActivePage ();
ASSERT (pPage);
pPage->MoveWindow (&m_rctPage);
return 0;
}
BOOL CMySheet::OnCommand(WPARAM wParam, LPARAM lParam)
{
// the sheet resizes the page whenever the Apply button is clicked so we need to size it correctly
if (ID_APPLY_NOW == wParam ||
ID_WIZNEXT == wParam ||
ID_WIZBACK == wParam)
PostMessage (WM_RESIZEPAGE);
return CPropertySheet::OnCommand(wParam, lParam);
}