0368 隨機更換背景的窗體
如果用戶使用軟件頻率非常高,可以爲程序設計可以隨機更換背景的功能,這樣不但可以使用戶心情愉快,也增加了軟件的人性化設計。
向工程中導入幾幅不同的圖片,然後使用srand函數以系統時間設置隨機種子,使程序可以隨機更換背景,如圖6.16所示。
圖6.16 隨機更換背景的窗體
程序代碼如下:
BOOL CRandBKDlg::OnInitDialog()
{
……//此處代碼省略
CTime Time;
Time = CTime::GetCurrentTime();
srand(Time.GetSecond());
int i = rand()%4;
m_Picture.SetBitmap(LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1+i))); //設置位圖
return TRUE;
}
0369 顯示歡迎窗體
有時因爲要從數據庫中裝入大量數據或者要裝入一些大型位圖而使程序界面在啓動時顯示得較 慢,這時可能希望在啓動時給出一個快速顯示的窗體,這種窗體也被叫做“歡迎窗體”,一般用於顯示諸如應用程序名、版權信息和一個簡單的位圖等內容。可以通 過定時器來控制歡迎窗體的顯示時間,如圖6.17所示。
圖6.17 顯示歡迎窗體
程序代碼如下:
BOOL CBegin::OnInitDialog()
{
CDialog::OnInitDialog();
SetTimer(1,2000,NULL);
return TRUE;
}
void CBegin::OnTimer(UINT nIDEvent)
{
KillTimer(1);
CDialog::OnCancel();
CDialog::OnTimer(nIDEvent);
}
0370 顯示關於窗體
在創建MFC Application Wizard的應用程序時,默認情況下關於窗體就已經被創建了,並關聯了一個CAboutDlg類,顯示時只要使用CAboutDlg類對象調用DoModal方法就可以了。如圖6.18所示。
圖6.18 顯示關於窗體
程序代碼如下:
void CShowAboutDlg::OnButton1()
{
CAboutDlg dlg;
dlg.DoModal();
}
0371 不使用ESC鍵關閉窗體
在編寫應用程序時,有時不想要按ESC鍵就關閉窗體,這就需要在虛函數PreTranslateMessage(MSG* pMsg)中將ESC鍵按下時的消息截獲,然後返回空。
程序代碼如下:
BOOL CBanESCDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN && pMsg->wParam == 27)
return NULL;
return CDialog::PreTranslateMessage(pMsg);
}
0372 關閉窗體前彈出確認對話框
爲了不因爲誤操作關閉窗體,可以在關閉窗體時設置一個提示框,判斷是否關閉窗體。通過MessageBox函數可以添加消息框。如圖6.19所示。
圖6.19 關閉窗體前彈出確認對話框
程序代碼如下:
void CCloseDlg::OnCancel()
{
if(MessageBox("確認是否退出程序","系統提示",MB_YESNO
| MB_ICONQUESTION) == IDYES)
{
CDialog::OnCancel();
}
}
0373 如何在主窗體顯示前彈出登錄框
要在主窗體顯示前彈出登錄框,可以在主窗體的OnInitDialog函數中使用DoModal方法顯示登錄框,然後通過判斷DoModal方法的返回值是否等於IDOK來確定是否顯示主窗體。如圖6.20所示。
程序代碼如下:
BOOL CShowLoginDlg::OnInitDialog()
{
……//此處代碼省略
CLogin dlg;
if(dlg.DoModal() != IDOK)
{
OnOK();
}
return TRUE;
}
圖6.20 登錄框
0374 設置對話框背景顏色
設置對話框背景顏色可以通過SetDialogBkColor函數來實現。如圖6.21所示。
圖6.21 登錄框
程序代碼如下:
BOOL CColorApp::InitInstance()
{
AfxEnableControlContainer();
SetDialogBkColor(RGB(0,0,255));
…… //此處代碼省略
}
0375 使用畫刷繪製背景顏色
使用畫刷也可以繪製背景顏色,只要獲得窗體的客戶區域,然後使用FillRect方法進行填充就可以繪製背景顏色。如圖6.22所示。
程序代碼如下:
HBRUSH CBrushBKDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
CBrush m_brush;
m_brush.CreateSolidBrush(RGB(255,0,0));
CRect m_rect;
GetClientRect(m_rect);
pDC->SelectObject(&m_brush);
pDC->FillRect(m_rect,&m_brush);
return m_brush;
}
圖6.22 使用畫刷繪製背景顏色
0376 設置窗體顏色漸變
要實現窗體顏色漸變,需要重載對話框的OnPaint函數,在OnPaint函數中通過畫刷和CDC的FillRect方法來進行顏色的漸變。如圖6.23所示。
圖6.23 設置窗體顏色漸變
程序代碼如下:
void CColorChangeDlg::OnPaint()
{
CPaintDC dc(this);
CBrush brush;
CRect rect;
GetClientRect(&rect);
for(int m=255;m>0;m--)
{
int x,y;
x = rect.Width() * m / 255;
y = rect.Height() * m / 255;
brush.DeleteObject();
brush.CreateSolidBrush(RGB(255,m,0));
dc.FillRect(CRect(0,0,x,y),&brush);
}
}
0377 將對話框以位圖形式保存到磁盤中
在設計抓圖軟件時,經常需要將一些對話框保存成位圖存儲到磁盤中。那麼在Visual C++ 6.0中該如何實現該功能呢?
要實現該功能,用戶需要對位圖文件的結構有所瞭解。位圖文件由位圖文件頭 BITMAPFILEHEADER、位圖信息頭BITMAPINFOHEADER、調色板Palette和位圖實際數據4部分組成。如果在程序中獲得了這 些數據,就可以保存成位圖了。那麼如何從對話框中獲得這些數據呢?首先需要獲得對話框的設備環境,然後將其繪製到CBitmap對象中,最後通過 CBitmap對象獲取位圖文件的各個部分。程序相關代碼如下:
void CSaveDialogDlg::OnButtionsave()
{
CDC* pDC = GetWindowDC();
CBitmap bitmap;
CDC memDC ;
CRect rect;
GetWindowRect(rect);
memDC.CreateCompatibleDC(pDC);
bitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
memDC.SelectObject(&bitmap);
memDC.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);
CFileDialog fDlg(FALSE,"bmp",NULL,OFN_HIDEREADONLY |
OFN_OVERWRITEPROMPT,"位圖文件|*.bmp",this);
if (fDlg.DoModal()==IDOK)
{
CString bmpfile = fDlg.GetPathName();
CFile file(bmpfile,CFile::modeCreate|CFile::modeWrite);
BITMAP bInfo;
bitmap.GetBitmap(&bInfo);
//計算調色板大小
int panelsize = 0;
if (bInfo.bmBitsPixel<24) //非真彩色
{
panelsize = pow(2,bInfo.bmBitsPixel)*sizeof(RGBQUAD);
}
//定義位圖信息
BITMAPINFO* bMapInfo = (BITMAPINFO*)LocalAlloc(LPTR,
sizeof(BITMAPINFO)+panelsize);
bMapInfo->bmiHeader.biBitCount = bInfo.bmBitsPixel;
bMapInfo->bmiHeader.biClrImportant = 0;
bMapInfo->bmiHeader.biCompression = 0;
bMapInfo->bmiHeader.biHeight = bInfo.bmHeight;
bMapInfo->bmiHeader.biPlanes = bInfo.bmPlanes;
bMapInfo->bmiHeader.biSize = sizeof(BITMAPINFO);
bMapInfo->bmiHeader.biSizeImage = bInfo.bmHeight*bInfo.bmWidthBytes;
bMapInfo->bmiHeader.biWidth = bInfo.bmWidth;
bMapInfo->bmiHeader.biXPelsPerMeter = 0;
bMapInfo->bmiHeader.biYPelsPerMeter = 0;
//獲取位圖的實際數據
char* pData = new char[bMapInfo->bmiHeader.biSizeImage];
int len = GetDIBits(pDC->m_hDC,bitmap,
0,bInfo.bmHeight,pData,bMapInfo,DIB_RGB_COLORS);
BITMAPFILEHEADER bFileHeader;
bFileHeader.bfType = 0x4D42;
bFileHeader.bfReserved1 = 0;
bFileHeader.bfReserved2 = 0;
bFileHeader.bfSize = sizeof(BITMAPFILEHEADER);
bFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)+panelsize;
//向文件中寫入位圖數據
file.WriteHuge(&bFileHeader,sizeof(BITMAPFILEHEADER));
file.WriteHuge(&bMapInfo->bmiHeader,sizeof(BITMAPINFOHEADER));
file.WriteHuge(pData,bMapInfo->bmiHeader.biSizeImage+panelsize);
file.Close();
delete pData;
LocalFree(bMapInfo);
}
bitmap.DeleteObject();
memDC.DeleteDC();
}
0378 在對話框中顯示HTML文件
在開發應用程序時,有時需要在程序中瀏覽網頁中的內容,如果讓程序通過瀏覽器窗口瀏覽網頁,顯得有些不便,如果能在對話框中顯示網頁內容就好了。用戶可以通過調用MSHTML.DLL動態庫中的ShowHTMLDialog方法實現,效果如圖6.24所示。
圖6.24 在對話框中顯示HTML文件
程序相關代碼如下:
// 需要引用urlmon.h頭文件
// 定義函數原型
typedef HRESULT STDAPICALLTYPE TShowHTMLDlg (HWND hwndParent,
IMoniker *pm, VARIANT *pvIN, TCHAR* pOptions,VARIANT *pvOut);
void CDialogHtmlDlg::OnBrown()
{
//加載動態庫
CString urltext ;
m_Url.GetWindowText(urltext);
HINSTANCE hInstance = LoadLibrary("MSHTML.DLL");
if(hInstance)
{
TShowHTMLDlg *pfnShowDlg;
pfnShowDlg = (TShowHTMLDlg*)GetProcAddress(hInstance,"ShowHTMLDialog");
if(pfnShowDlg)
{
IMoniker *moniker=NULL;
if( CreateURLMoniker(NULL,urltext.AllocSysString(),&moniker)==S_OK)
{
pfnShowDlg(m_hWnd,moniker,NULL,NULL,NULL);
if(moniker!=NULL)
moniker->Release();
}
}
FreeLibrary(hInstance);
}
0379 在對話框中創建視圖
在MFC應用程序中,通常是在文檔"視圖結構的應用程序中使用視圖對象。其實,在基於對話框的應用程序中也可以使用視圖對象。本例在對話框中創建了一個視圖,並在視圖中繪製一幅背景圖片,效果如圖6.25所示。
圖6.25 在對話框中創建視圖
視圖對象的創建是通過調用Create方法,並提供了一個pContent參數實現的。因此,只要提供了pContent參數,就可以創建視圖對象了。首先從CView類派生一個子類,然後在對話框類中添加CreateView方法創建視圖。
CView* CDlgViewDlg::CreateView()
{
CCreateContext Content;
Content.m_pCurrentFrame = (CFrameWnd*)this;
Content.m_pNewDocTemplate = NULL;
Content.m_pCurrentDoc = NULL;
Content.m_pLastView = NULL;
Content.m_pNewViewClass = RUNTIME_CLASS(CDlgView);
CView* pTemp = (CView*)Content.m_pNewViewClass->CreateObject();
pTemp->Create(NULL,NULL
,AFX_WS_DEFAULT_VIEW,CRect(0,0,0,0),this,AFX_IDW_PANE_FIRST,&Content);
return (CDlgView*)pTemp;
}
最後在對話框初始化時調用CreateView方法創建視圖。
m_ClientView = (CDlgView*)CreateView();
CRect rect;
GetClientRect(rect);
m_ClientView->MoveWindow(rect);
0380 如何共享對話框資源
在設計程序時,如果兩個模塊使用的對話框資源完全相同,可以讓這兩個模塊共享一個對話框資源,如圖6.26、圖6.27所示。
圖6.26 圖書信息 圖6.27 商品信息
爲了實現對話框資源的共享,首先需要創建一個對話框資源,在對話框資源中放置相應的控件。然後創建兩個對話框類,將“enum { IDD = 對話框資源ID};”語句添加到每個對話框類中。最後利用類嚮導爲每個對話框類中的控件命名。這樣,就實現了對話框資源的共享。
0381 如何實現窗體繼承
在Delphi或C#中,利用工程嚮導可以方便地實現窗體的繼承。在Visual C++中,如何實現窗體的繼承呢?本例實現了該功能,效果如圖6.28、圖6.29所示。
圖6.28 父窗體 圖6.29 子窗體
爲了實現窗體的繼承,首先在父窗體(本例爲CInheritedFormDlg)中修改構造函數,格式如下:
CInheritedFormDlg(CWnd* pParent = NULL, UINT ID = IDD_INHERITEDFORM_DIALOG);
然後從CDialog類派生一個子類,本例爲CChildDlg。修改該類的父類爲CInheritedFormDlg。
最後修改子類的構造函數及消息映射,代碼如下:
CChildDlg::CChildDlg(CWnd* pParent /*=NULL*/)
: CInheritedFormDlg(pParent)
{
}
BEGIN_MESSAGE_MAP(CChildDlg, CInheritedFormDlg)
//{{AFX_MSG_MAP(CChildDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
這樣就實現了窗體的繼承。
0382 怎樣使對話框的關閉按鈕變灰
許多應用程序中對話框的關閉按鈕是不可用的。但是,在Visual C++的對話框屬性窗口中並沒有設置該屬性的選項。那麼如何使對話框的關閉按鈕變灰呢?用戶可以在對話框初始化時調用下面的代碼實現:
CMenu *pMenu=GetSystemMenu(FALSE);
int count =pMenu->GetMenuItemCount( );
UINT MenuID=pMenu->GetMenuItemID(count-1);
pMenu->EnableMenuItem(MenuID, MF_DISABLED);
0383 模式對話框與非模式對話框的使用
模式對話框在顯示時會阻塞當前線程的執行,直到模式對話框關閉。因此模式對話框的創建通常採用局部變量的形式。例如:
CBeautifulMenuDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
非模式對話框的顯示不會阻塞當前線程的執行,如果採用局部變量的形式創建,則對話框創建後會立即釋放,因爲局部變量失去了作用域,對話框窗口資源會被釋放。因此,對於非模式對話框,通常採用成員變量的形式創建。例如:
Dlg.Create(IDD_YUYY_DIALOG,this); //Dlg是當前對話框類的一個成員
Dlg.ShowWindow(SW_SHOW);
0384 在對話框中使用CDialogBar
在程序中使用對話欄CDialogBar,能夠將控件分組,對話欄類似於一個容器,其中可以放置各種控件。那麼如何在對話框中使用對話欄控件呢?本例實現了該功能,效果如圖6.30所示。
圖6.30 在對話框中使用CDialogBar
爲了使用對話欄控件,首先從CDialog派生一個子類,本例爲CCustomBar,修 改該類的父類爲CDialogBar,在CCustomBar類的構造函數將初始化部分的代碼註釋,在消息映射部分,將CDialog修改爲 CDialogBar。然後修改對話框資源的屬性,使對話框具有“Child”和“Control”風格。最後修改CCustomBar的 PreTranslateMessage方法,防止在對話欄中按<Esc>鍵關閉對話框。程序主要代碼如下:
BOOL CCustomBar::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message==WM_KEYDOWN)
if (pMsg->wParam == VK_ESCAPE)
return true;
return CDialogBar::PreTranslateMessage(pMsg);
}
void CCustomBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CDialogBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);
}
void CCustomBar::OnSysCommand(UINT nID, LPARAM lParam)
{
if (nID ==SC_CLOSE )
this->CloseWindow();
CDialogBar::OnSysCommand(nID, lParam);
}
0385 如何在基於對話框的程序中爲控件設置提示信息
在基於對話框的應用程序中爲控件設置提示信息需要兩個步驟:一是調用控件的EnableToolTips方法激活控件提示信息。二是處理TTN_NEEDTEXT消息,在對話框的消息映射部分添加ON_NOTIFY_EX映射宏。例如:
BOOL CMyFormView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID =pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
nID = ::GetDlgCtrlID((HWND)nID);
if(nID)
{
pTTT->lpszText = MAKEINTRESOURCE(nID);
pTTT->hinst = AfxGetResourceHandle();
return(TRUE);
}
}
return(FALSE);
}