【目 录】
1. 让程序只运行一次
2. 改变对话框的背景颜色
3. 让程序前端显示
4. “显示”链接 LIB 文件
5. 关闭其它应用程序
6. 系统托盘
7. 创建隐藏的对话框
8. 怎样使用高版本的函数和宏
9. 如何以动态的效果打开对话框
10. 怎样以渐隐方式关闭对话框
11. 动态改变光标
12. 重写标题栏上的关闭按钮
13. 重写 F1 帮助
★ 让程序只运行一次
在源程序中的应用程序类的初始化函数【 InitInstance() 】中,添加以下代码:
CreateMutex( NULL, FALSE, "Application Mutex" );// 添加互斥量
if(GetLastError()==ERROR_ALREADY_EXISTS)
return FALSE;
注意:要在函数的开始处添加代码。
返 回
★ 改变对话框的背景颜色
在对话框类的实现以前完成。同样,在应用程序类的初始化函数【 InitInstance() 】中,添加如下代码:
SetDialogBkColor(RGB(160,180,220),RGB(0,0,0));

// 注意第一个 RGB 是背景颜色,第二个 RGB 是前景颜色(文字)
// 也就是说,默认的第二个 RGB(0,0,0) ,而且在 VC 7.0 中有问题
注意:尽量在应用程序弹出对话框以前添加代码。
返 回
★ 让对话框始终显示在最前端
只需要一个 API 函数【 SetWindowPos() 】就可以了,具体的函数参看下面:
BOOL SetWindowPos( HWND hWnd , // handle to window
HWND hWndInsertAfter, // placement-order handle
int X , // horizontal position
int Y , // vertical position
int cx, // width
int cy, // height
UINT uFlags // window-positioning flags );
下面给出一个例子,让对话框在最前端(显示)运行。
// 在对话框的初始化函数中的合适地方添加如下代码。
// TODO: Add extra initialization here
::SetWindowPos(this->m_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);

return TRUE; // return TRUE unless you set the focus to a control
返 回
★ “显示”链接 LIB 文件
如果程序中使用了动态链接库( DLL ),而又非使用 LoadLibrary() 加载,那么在编译的时候需要在工程选项中的 Link 选项中手工添加所需的 Lib 文件。如果不想那么麻烦,也可以手工添加,即“显示”添加。添加的过程如下:在 .CPP 文件的首部,即在 #include "headfile.h" 后面加上 #pragma comment(lib,"Library.lib") 即可。好像在 .h 后面添加此句也可以的。
返 回
★ 关闭其它应用程序
想要关闭其它应用程序,只需要找到该应用程序的句柄,给其发关闭命令即可。具体实现参见下面代码:
void CloseOthers()
{

// 定义一个应用程序句柄的指针
CWnd *pCwnd;

// 用 FindWindow 函数找到想要关闭的应用程序的句柄的指针
pCwnd=FindWindow("lpszClassName","pszWindowName");

// 如果返回成功
if( pCwnd )
pCwnd->SendMessage(SW_CLOSE);// 给其发送关闭的消息
}
返 回
★ 系统托盘
如果将自己做的程序添加到系统托盘中,会给人一种你的程序很专业的感觉。其实要操作系统托盘很简单。首先,在对话框的头文件中添加自定义消息:
#define WM_TASKBAR WM_APP+1000

然后映射自定义消息,在如下地方添加代码:

BEGIN_MESSAGE_MAP(CMyDlg, CDialog)

// 在此处添加
ON_MESSAGE(WM_TASKBAR,OnTaskbar)

//{{AFX_MSG_MAP(CAddiconDlg)
ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_COMMAND(ID_MENUQUIT, OnMenuquit)

//}}AFX_MSG_MAP
END_MESSAGE_MAP()
然后就是编写处理自定义消息的函数(右键单击弹出菜单):
LRESULT CMyDlg::OnTaskbar(WPARAM wParam, LPARAM lParam)

{

if( lParam == WM_RBUTTONDOWN )

{

CMenu* menu;

menu = new CMenu();

menu->LoadMenu(IDR_MENU1); // 菜单是要提前做好的
CMenu* pPopup=menu->GetSubMenu(0);

::SetMenuDefaultItem(pPopup->m_hMenu,0,TRUE); // 设置粗体字
CPoint Point;

GetCursorPos(&Point);

SetForegroundWindow(); // 鼠标在菜单之外的地方点击便隐藏菜单
pPopup->TrackPopupMenu(TPM_LEFTALIGN,Point.x,Point.y,AfxGetMainWnd(),NULL);

}

return 0;

}
接下来是向系统托盘中加入图标,用函数来表示:
void CMyDlg::AddIcon()

{

// 图标句柄
HICON hIcon;

char lpszTip[] = " 欢迎使用本程序! ";

HINSTANCE hInst = AfxFindResourceHandle(

MAKEINTRESOURCE(IDR_MAINFRAME),RT_GROUP_ICON);

hIcon = (HICON)LoadImage(hInst,MAKEINTRESOURCE(IDR_MAINFRAME),

IMAGE_ICON,16,16,LR_DEFAULTCOLOR);

// 给 NOTIFYICONDATA 结构赋值
NOTIFYICONDATA tnid;

tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = m_hWnd;
tnid.uID = IDR_MAINFRAME;
tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
tnid.uCallbackMessage = WM_TASKBAR; // 自定义消息
tnid.hIcon = hIcon;

if (lpszTip)
lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));
else
tnid.szTip[0] = '\0';

// 调用 Shell_NotifyIcon 函数通过 NIM_ADD 向任务栏写图标
Shell_NotifyIcon(NIM_ADD, &tnid);

// 释放图标资源
if (hIcon)
DestroyIcon(hIcon);
}

最后是编写删除托盘图标的函数:
void CMyDlg::DelIcon()

{

// 提供结构大小,窗口句柄和图标 ID
NOTIFYICONDATA tnid;

tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = m_hWnd;
tnid.uID = IDR_MAINFRAME;

// 用 NIM_DELETE 删除图标
Shell_NotifyIcon(NIM_DELETE, &tnid);
}
返 回
★ 创建一个没有窗口的对话框
有时候,需要让一些程序运行的时候,不显示主窗口。感觉应该有两种办法,第一种是设置定时器,在程序运行的开始很短的一段时间内就调用 ShowWindow() 函数隐藏窗口。第二种方法是重写应用程序类的初始化函数,具体代码如下:
BOOL CMyApp::InitInstance()

{

AfxEnableControlContainer();

// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.

#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif

CMyDlg *pdlg = new CMyDlg;

m_pMainWnd = pdlg;

pdlg->ShowWindow(SW_HIDE);

// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return true;

}
注意比较和原来的代码有什么区别。以上代码在 Debug 模式下编译运行以后,有点问题,但在 Release 模式下一切都没有问题。不知道是为什么。
返 回
★ 怎样使用高版本的函数和宏
在开发应用程序的时候,我们可能会使用一些对版本要求比较高的函数和宏定义,所以需要做一些设置,否则编译器不会通过的,给出一个没有定义的消息。如何让编译器认识这些东西呢?就需要我们做点工作,如下:
// 在应用程序头文件的开始位置设置版本号
#undef WINVER
#define WINVER 0X500
返 回
★ 如何以动态的效果打开对话框
下面介绍如何让对话框以动态的效果弹出。
// 定义对话框类的成员变量
int m_nWidth,m_nHeight;
int m_nDx,m_nDy;
int m_nDx1,m_nDy1;
在对话框的初始化函数中添加如下代码:
// 获得窗口预设的大小
CRect dlgRect;
GetWindowRect(dlgRect);
CRect desktopRect;

// 将窗口开始大小设为 0
GetDesktopWindow()->GetWindowRect(desktopRect);
MoveWindow((desktopRect.Width() - dlgRect.Width()) / 2, (desktopRect.Height() - dlgRect.Height()) / 2, 0, 0 );

// 初始化变化大小
m_nWidth=dlgRect.Width();
m_nHeight=dlgRect.Height();
m_nDx=2; m_nDy=4;
m_nDx1=2; m_nDy1=2;

// 设定定时器
SetTimer(1,10,NULL);
接下来就是编写定时器代码,参见下面的程序段:
// 获得此时窗口的实际大小
CRect dlgRect;
GetWindowRect(dlgRect);

// 获得桌面的大小
CRect desktopRect;

GetDesktopWindow()->GetWindowRect(desktopRect);

// 如果是窗口弹出过程,则逐渐增大窗口
if(nIDEvent == 1)
{

MoveWindow( (-m_nDx+desktopRect.Width() - dlgRect.Width()) / 2, (-m_nDy+desktopRect.Height() - dlgRect.Height()) / 2, +m_nDx+dlgRect.Width(), +m_nDy+dlgRect.Height() );

// 不要超过窗口预设的宽度
if(dlgRect.Width() >=m_nWidth)
m_nDx=0;

// 不要超过窗口预设的高度
if(dlgRect.Height() >=m_nHeight)
m_nDy=0;

// 停止变化,关闭定时器 1
if((dlgRect.Width() >=m_nWidth) && (dlgRect.Height() >=m_nHeight))
KillTimer(1);
}

// 停止变化,关闭定时器 1
if((dlgRect.Width() >=m_nWidth) && dlgRect.Height() >=m_nHeight))
KillTimer(1);
下面还以一种办法,就是使用 Windows 的高级函数,需要显示的定义版本号,方法参见上一部分(如何使用高版本的函数和宏定义)。具体使用函数的办法如下:
// 函数原型:
BOOL AnimateWindow ( HWND hWnd , DWORD dwTime , DWORD dwFlags )
/******************************************************************
函数功能:该函数能在显示与隐藏窗口时产生两种特殊类型的动画效果:滚动动画和滑动动画。
参数含义:
hWnd : 指定产生动画的窗口的句柄。
dwTime:指明动画持续的时间(以微秒计),完成一个动画的标准时间为200微秒。 dwFags:指定动画类型。这个参数可以是一个或多个下列标志的组合。标志描述: AW_SLIDE:使用滑动类型。缺省则为滚动动画类型。当使用AW_CENTER标志时,这个标志就被忽略。 AW_ACTIVATE:激活窗口。在使用了AW_HIDE标志后不能使用这个标志。 AW_BLEND:实现淡出效果。只有当hWnd为顶层窗口的时候才可以使用此标志。 AW_HIDE:隐藏窗口,缺省则显示窗口。 AW_CENTER:若使用了AW_HIDE标志,则使窗口向内重叠,即收缩窗口;若未使用AW_HIDE标志,则使窗口向外扩展,即展开窗口。 AW_HOR_POSITIVE:自左向右显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。 AW_VER_POSITIVE:自顶向下显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。 AW_VER_NEGATIVE:自下向上显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。
返 回
★ 怎样以渐隐方式关闭对话框
在应用程序的退出消息中添加如下代码:(详细说明见上面)
// 以下函数需要 5.0 及其以上版本支持
AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);
返 回
★ 动态改变光标
以下代码解决当鼠标器指向某一个控件的时候动态改变光标。
// 重载对话框的下面这个虚函数
BOOL CRgnWDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{

// TODO: Add your message handler code here and/or call default
switch(pWnd->GetDlgCtrlID()) // 得到鼠标所在位置的控件的 ID 号
{
case IDOK:
{
SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR1));
return TRUE;
}

default:
{
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
return TRUE;
}

}

return CDialog::OnSetCursor(pWnd, nHitTest, message);

}
返 回
★ 重写标题栏上的关闭按钮
有一些软件,当用户单击标题栏上的关闭按钮的时候,程序并没有结束运行,而是最小化了,下面的代码就是解决这个问题的。
// 重载下面的函数
void CRecorderDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if (nID == SC_CLOSE)
// 自定义的函数或代码
else
CDialog::OnSysCommand(nID, lParam);
}
返 回
★ 重写 F1 帮助
在应用程序中,如果按 F1 键的话,系统会默认的调用与应用程序同名的 HLP 文件,但我们往往使用 CHM 格式的帮助文件,如果响应 F1 呢?方法就是重载对话框的 WinHelp ()这个虚函数。代码如下:
void CMyDlg::WinHelp(DWORD dwData, UINT nCmd)
{
// TODO: Add your specialized code here and/or call the base class
if( GetKeyState (VK_F1) < 0 )
{
AfxMessageBox("you press F1");
return;
}
CDialog::WinHelp(dwData, nCmd);
}
返 回
2004年2月心得