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);
}