前段時間,一個底層開發的同事寫一個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);
}