2005年12月02日

两个小程序,学习《Programming windows with MFC》时完成的两个作业,实现MFC的一些简单应用

1, 菜单、绘图、字体、ToolTips、scroolview

2,类似windows的paint程序,画一些几何图形,并实现了视图间的切换

  消息是windows操作系统和应用程序之间进行通信的载体,操作系统将包括用
户在内的各种事件以消息的形式发送至目标,目标系统再根据消息具体的内容进
行相应的处理。
  在VC++6.0中,大多数的窗口消息可以从ClassWizard中找到,但是一些不
常用的消息在ClassWizard中并没有封装,比如热键处理消息(WM_HOTKEY),用
户必须事先定义热键,然后不论该程序在前台或后台运行,只要用户按下了这个
热键,该程序就会立即在前台运行,并收到热键消息,消息处理函数执行热键中
定义的操作。要实现这些功能,用户必须在代码级进行工作,也就是说要手工编
写代码。具体步骤如下:
  假设用户已经用AppWizard生成了一个单文档界面框架,在工程中主要有下列
几个文件,向导为应用程序创建了如下类:
  CtestView CtestDoc CtestApp CmainFrame CAboutDlg
  请按下列步骤进行:
  1、在视图类的声明文件中,即testview.h文件中,找到消息映射的声名处,
在下列语句处加入热键处理函数声明:(划线部分)
   //{{AFX_MSG(CTestView)
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
   //}}AFX_MSG
  LRESULT OnHotKey(WPARAM wParam,LPARAM lParam);
   DECLARE_MESSAGE_MAP()
  2、在视图类的实现文件,即TestView.cpp文件中,找到消息映射的定义处,
这里是使函数和消息发生关联的地方,当发生某消息时,会调用这里定义的相应
消息处理函数,也就是说用消息映射宏使消息与相应的处理函数发生关系。

  下面的语句说明WM_HOTKEY消息和OnHotkey函数发生关联。
   BEGIN_MESSAGE_MAP(CTestView, CView)
   //{{AFX_MSG_MAP(CTestView)
   ON_WM_CREATE()
   //}}AFX_MSG_MAP
   // Standard printing commands
   ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
   ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
   ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
   ON_MESSAGE(WM_HOTKEY,OnHotkey) //消息和函数发生关联
  END_MESSAGE_MAP()
  3、在OnCreate函数中加入初始化代码,向系统登记热键。
   RegisterHotKey(hWnd,1001,MOD_CONTROL|MOD_ALT,‘z’);
   RegisterHotKey(hWnd,1002,MOD_CONTROL|MOD_ALT,‘Z’);
  本例中定义的热键为Ctrl+Alt+z。
  4、在OnHotkey()处理函数中处理热键,即检查是否是所期望的热键,如果是
,这里为了简单,弹出一个对话框,显示“You Press Ctrl+Alt+z(Z)”。
  LRESULT CTestView::OnHotkey(WPARAM wParam,LPARAM lParam)
  {
   if(wParam==1001||wParam==1002)
   MessageBox(“You Press Ctrl+Alt+z(Z)”);
  return 0;
  }
  注意:OnHotkey()函数必须有返回值。
  5、最后,不要忘了在OnDestroy()函数中解除函数登记,释放系统资源。
  UnregisterHotKey(m_hWnd,1001);
  UnregisterHotKey(m_hWnd,1002);
  这样程序运行后,无论程序在前台或后台运行,只要你按下Ctrl+Alt+z,就
会执行热键处理函数中的代码,这里弹出对话框。读者可以自行在自己的热键处
理函数中加入需要的代码来完成特定的功能。该程序在Pwin98平台上,在Visual
C++6.0中调试通过。
  (沈阳 金波)

函数功能:该函数定义一个系统范围的热键。

    函数原型:BOOL RegisterHotKey(HWND hWnd,intid,UINT fsModifiers,UINT vk);

    参数:

    hWnd:接收热键产生WM_HOTKEY消息的窗口句柄。若该参数NULL,传递给调用线程的WM_HOTKEY消息必须在消息循环中中进行处
理。

    id:定义热键的标识符。调用线程中的其他热键不能使用同样的标识符。应用功能程序必须定义一个0X0000-0xBFFF范围的值。一个共享
的动态链接库(DLL)必须定义一个0xC000-0xFFFF范围的值伯GlobalAddAtom函数返回该范围)。为了避免与其他动态链接库定义的热键冲
突,一个DLL必须使用GlobalAddAtom函数获得热键的标识符。

    fsModifoers:定义为了产生WM_HOTKEY消息而必须与由nVirtKey参数定义的键一起按下的键。该参数可以是如下值的组合:

    MOD_ALT:按下的可以是任一Alt键。MOD_CONTROL:按下的可以是任一Ctrl键。

    MOD_SHIFT:按下的可以是任一Shift键。

    MOD_WIN:按下的可以是任一Windows按键。这些键可以用Microsoft Windows日志记录下来。

    vk:定义热键的虚拟键码。

    返回值:若函数调用成功,返回一个非O值。若函数调用失败,则返回值为0。若要获得更多的错误信息,可以调用GetLastError函数。

    备注:当某键被接下时,系统在所有的热键中寻找匹配者。一旦找到一个匹配的热键,系统将把WM_HOTKEY消息传递给登记了该热键
的线程的消息队列。该消息被传送到队列头部,因此它将在下一轮消息循环中被移去。该函数不能将热键同其他线程创建的窗口关联起
来。

    若为一热键定义的击键己被其他热键所定义,则RegisterHotKey函数调用失败。

    若hWnd参数标识的窗口已用与id参数定义的相同的标识符登记了一个热键,则参数fsModifiers和vk的新值将替代这些参数先前定义的值。

    Windows CE:Windows CE 2.0以上版本对于参数fsModifiers支持一个附加的标志位。叫做MOD_KEYUP。

    若设置MOD_KEYUP位,则当发生键被按下或被弹起的事件时,窗口将发送WM_HOTKEY消息。

    RegisterHotKey可以被用来在线程之间登记热键。

    速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:不支持;头文件:winuser.h;库文件:user32.lib。
 

      在使用vc写简繁体通用程序时,对实现菜单、界面、Tooltips等的文字时无法实现通用。如果写简体和繁体各一套程序,那肯定不现实。查找所有资料和文章都只能实现菜单的多语言,且使用起来也不方便;并且无法实现界面、Tooltips等的多语言。因而,采用纯资源的DLL文件来实现多语言。

      纯资源DLL文件实现步骤如下:

      (1)创建简繁体MDI或SDI程序后,把VC框架自动创建的.rc,.rc2,.ico,.bmp等文件从程序框架中删除;

      (2)使用Projects的Win32 Dynamic-Link Library分别创建简繁体纯资源dll文件,把由MDI或SDI程序创建的.rc,.rc2,.ico,.bmp等文件加入到该工程文件中;

     (3)在Project菜单项选择Settings然后选择Project Settings的Link标签;然后在Project Options框内输入/NOENTRY。编译后就产生纯资源DLL文件;

     纯资源DLL文件加入没有任何资源的MDI或SDI程序,其步骤如下:

     (1)在主应用程序类的.h文件中定义protected 的 HINSTANCE 类型变量(如:mhInstMenu);    

  (2)在主应用程序类的.cpp文件::InitInstance()函数过程中添加下面代码:

    mhInstMenu = ::LoadLibrary("Menu.dll");  // Menu.dll为多语言纯资源的dll文件

    if (mhInstMenu == NULL) 

    { 

        return FALSE; // failed to load the localized resources 

    } 

    else { 

        AfxSetResourceHandle(m_hInstMenu); // get resources from the DLL 

    }
     (3)在主应用程序类的.cpp文件::ExitInstance()函数过程中添加下面代码:

FreeLibrary(mhInstMenu);

 

注意:Menu.dll文件可以有三种放置方法:

    A、和.exe文件在同一个路径下面;

    B、放在Windows98的System或Windows2000的System32路径下面;

    C、放在通过Path设置的路径下面。

具体方法如下:新建一个 dll 项目,然后把你程序的资源文件复制到 dll 项目资源中即可,接下来,修改 dll 项目中资源的语言(这可能需要花一点时间)。然后只要简单修改一下你的程序代码就可以了:

在 CWinApp 继承类中,添加一个成员变量(我使用的是日语):


HINSTANCE hJapaneseDll //Global var
…..
在 InitInstance 中添加一下代码(粗体部分是我添加的):

CMultiLangApp::InitInstance()
{
……
//Get Language Setting from INI
uLanguage = GetProfileInt("Language", "Language",0);

if (uLanguage == 1)
{
//Language is set for Japanese.
hJapaneseDll = AfxLoadLibrary("Japanese.dll");
ASSERT(hJapaneseDll);
AfxSetResourceHandle(hJapaneseDll);
}
…..
//create dialog or main frame
…..
}
最后,你可以添加一个菜单项或者单选按钮,用于切换语言,具体请看代码

来自:yesky
如何制作透明窗体

  使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。 

  SetLayeredWindowAttributes的函数原型如下:

BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window
COLORREF crKey, // specifies the color key
BYTE bAlpha, // value for the blend function
DWORD dwFlags // action
);

Windows NT/2000/XP: Included in Windows 2000 and later.
Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的)
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.
 

  一些常量:
 

WS_EX_LAYERED = 0×80000;
LWA_ALPHA = 0×2;
LWA_COLORKEY=0×1;

  其中dwFlags有LWA_ALPHA和LWA_COLORKEY

  LWA_ALPHA被设置的话,通过bAlpha决定透明度.

  LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示.

  要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0×80000).

  例子代码:

  在OnInitDialog()加入:

//加入WS_EX_LAYERED扩展属性
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0×80000);
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
 typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
 MYFUNC fun = NULL;
 //取得SetLayeredWindowAttributes函数指针
 fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
 if(fun)fun(this->GetSafeHwnd(),0,128,2);
 FreeLibrary(hInst);
}

  稍加修改还可以作出淡出淡入的效果. 注意第三个参数(128)不要取得太小了,为0的话就完全透明,看不到了。

  如何使框架窗口的图标为动画显示

  可以用TIMER,但是TIMER不能有效的定时。因为TIMER发送的是窗口消息,当窗口忙于处理键盘、鼠标等消息时就不能及时处理TIMER,会使间隔时间变得很长 。

  可以考虑用一个单独得TIMER线程,用Sleep()定时来解决此问题。
 

UINT Timer(LPVOID param)
{
 HWND hWnd=(HWND)param;
 while(1)
 {
  Sleep(ms);
  PostMessage(hWnd,CH_PICTURE,NULL,NULL)
 }
}

  Sleep(ms)后发送自定义消息。消息处理函数就选择某一个ICON或BITMAP来显示。如 :
 

MyBotton.SetBitmap((HBITMAP)Bitmap[i]);

  Bitmap是一个位图数组,存放有j个位图。消息处理函数运行一次,i就累加一次,当i==j时,i就回到0;

  防止窗口闪烁的方法

  1、将Invalidate()替换为InvalidateRect()。

  Invalidate()会导致整个窗口的图象重画,需要的时间比较长,而InvalidateRect()仅仅重画Rect区域内的内容,所以所需时间会少一些。虫虫以前很懒,经常为一小块区域的重画就调用Invalidate(),不愿意自己去计算需要重画的Rect,但是事实是,如果你确实需要改善闪烁的情况,计算一个Rect所用的时间比起重画那些不需要重画的内容所需要的时间要少得多。

  2、禁止系统搽除你的窗口。

  系统在需要重画窗口的时候会帮你用指定的背景色来搽除窗口。可是,也许需要重画的区域也许非常小。或者,在你重画这些东西之间还要经过大量的计算才能开始。这个时候你可以禁止系统搽掉原来的图象。直到你已经计算好了所有的数据,自己把那些需要搽掉的部分用背景色覆盖掉(如:dc.FillRect(rect,&brush);rect是需要搽除的区域,brush是带背景色的刷子),再画上新的图形。要禁止系统搽除你的窗口,可以重载OnEraseBkgnd()函数,让其直接返回TRUE就可以了。如

BOOL CMyWin::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
//return CWnd::OnEraseBkgnd(pDC);//把系统原来的这条语句注释掉。
}

  3、有效的进行搽除。

  搽除背景的时候,不要该搽不该搽的地方都搽。比如,你在一个窗口上放了一个很大的Edit框,几乎占了整个窗口,那么你频繁的搽除整个窗口背景将导致Edit不停重画形成剧烈的闪烁。事实上你可以CRgn创建一个需要搽除的区域,只搽除这一部分。如

GetClientRect(rectClient);
rgn1.CreateRectRgnIndirect(rectClient);
rgn2.CreateRectRgnIndirect(m_rectEdit);
if(rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR) == ERROR)//处理后的rgn1只包括了Edit框之外的客户区域,这样,Edit将不会被我的背景覆盖而导致重画。
{
ASSERT(FALSE);
return ;
}
brush.CreateSolidBrush(m_clrBackgnd);
pDC->FillRgn(&rgn1,&brush);
brush.DeleteObject();

  注意:在使用这个方法的时候要同时使用方法二。别忘了,到时候又说虫虫的办法不灵。

  4、使用MemoryDC先在内存里把图画好,再复制到屏幕上。

  这对于一次画图过程很长的情况比较管用。毕竟内存操作比较快,而且复制到屏幕又是一次性的,至少不会出现可以明显看出一个东东从左画到右的情况。

void CMyWin::OnPaint()
{
CPaintDC dc1(this); // device context for painting
dcMemory.CreateCompatibleDC(&dc1);
CBitmap bmp;//这里的Bitmap是必须的,否则当心弄出一个大黑块哦。
bmp.CreateCompatibleBitmap(&dc1,rectClient.Width(),rectClient.Height());
dcMemory.SelectObject(&bmp);
//接下来你想怎么画就怎么画吧。
//dcMemory.FillRect(rectClient,&brush);

dc1.BitBlt(0,0,rectClient.Width(),rectClient.Height(),&dcMemory,0,0,SRCCOPY);
dcMemory.DeleteDC();
// Do not call CWnd::OnPaint() for painting messages
}
 

如何实现全屏显示

 

  全屏显示是一些应用软件程序必不可少的功能。比如在用VC++编辑工程源文件或编辑对话框等资源时,选择菜单“ViewFull Screen”,即可进入全屏显示状态,按“Esc”键后会退出全屏显示状态。

  在VC++6.0中我们用AppWizard按默认方式生成单文档界面的应用程序框架。下面将先讨论点击菜单项“ViewFull Screen”实现全屏显示的方法,再讲述按“Esc”键后如何退出全屏显示状态。

  1) 在CMainFrame类中,增加如下三个成员变量。

  private:
    WINDOWPLACEMENT m_OldWndPlacement; //用来保存原窗口位置
    BOOL m_bFullScreen; //全屏显示标志
    CRect m_FullScreenRect; //表示全屏显示时的窗口位置 

  2)在资源编辑器中编辑菜单IDR_MAINFRAME。在“View”菜单栏下添加菜单项“Full Screen”。在其属性框中,ID设置为ID_FULL_SCREEN,Caption为“Full Screen”。还可以在工具栏中添加新的工具图标,并使之与菜单项“Full Screen”相关联,即将其ID值也设置为ID_FULL_SCREEN。

  3)设计全屏显示处理函数,在CMainFrame类增加上述菜单项ID_FULL_SCREEN消息的响应函数。响应函数如下:
 

  void CMainFrame::OnFullScreen()
  {
GetWindowPlacement(&m_OldWndPlacement);
   CRect WindowRect;
   GetWindowRect(&WindowRect);
   CRect ClientRect;
   RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &ClientRect);
   ClientToScreen(&ClientRect);
   // 获取屏幕的分辨率
   int nFullWidth=GetSystemMetrics(SM_CXSCREEN);
   int nFullHeight=GetSystemMetrics(SM_CYSCREEN);
   // 将除控制条外的客户区全屏显示到从(0,0)到(nFullWidth, nFullHeight)区域, 将(0,0)和(nFullWidth, nFullHeight)两个点外扩充原窗口和除控制条之外的 客户区位置间的差值, 就得到全屏显示的窗口位置
   m_FullScreenRect.left=WindowRect.left-ClientRect.left;
   m_FullScreenRect.top=WindowRect.top-ClientRect.top;
   m_FullScreenRect.right=WindowRect.right-ClientRect.right+nFullWidth;
   m_FullScreenRect.bottom=WindowRect.bottom-ClientRect.bottom+nFullHeight;
   m_bFullScreen=TRUE; // 设置全屏显示标志为 TRUE
   // 进入全屏显示状态
   WINDOWPLACEMENT wndpl;
   wndpl.length=sizeof(WINDOWPLACEMENT);
   wndpl.flags=0;
   wndpl.showCmd=SW_SHOWNORMAL;
   wndpl.rcNormalPosition=m_FullScreenRect;
   SetWindowPlacement(&wndpl);

}
 

  4)重载CMainFrame类的OnGetMinMaxInfo函数,在全屏显示时提供全屏显示的位置信息。
 

  void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
  {
if(m_bFullScreen)
   {

lpMMI->ptMaxSize.x=m_FullScreenRect.Width();
   lpMMI->ptMaxSize.y=m_FullScreenRect.Height();
   lpMMI->ptMaxPosition.x=m_FullScreenRect.Width();
   lpMMI->ptMaxPosition.y=m_FullScreenRect.Height();
   //最大的Track尺寸也要改变
   lpMMI->ptMaxTrackSize.x=m_FullScreenRect.Width();
   lpMMI->ptMaxTrackSize.y=m_FullScreenRect.Height();
   }

CFrameWnd::OnGetMinMaxInfo(lpMMI) ;
  }
 

  完成上面的编程后,可以联编执行FullScreen.exe,选择菜单“ViewFull Screen”或点击与之关联的工具栏按钮即可进入全屏显示状态。但现在还需要增加用户退出全屏显示状态的操作接口,下面讲述如何编程实现按“Esc”键退出全屏显示状态。

  1)在ClassView中选中CMainFrame并单击鼠标右键,选择“Add Member Function…”,添加public类型的成员函数EndFullScreen,该函数将完成退出全屏显示的操作。
 

  void CMainFrame::EndFullScreen()
  {
if(m_bFullScreen)
   {// 退出全屏显示, 恢复原窗口显示
  ShowWindow(SW_HIDE);
   SetWindowPlacement(&m_OldWndPlacement);

}

}
 

  2)函数EndFullScreen可以退出全屏显示状态,问题是如何在“Esc”键被按下之后调用执行此函数。由于视图类可以处理键盘输入的有关消息(如WM_KEYDOWN表示用户按下了某一个键),我们将在视图类CFullScreenView中添加处理按键消息WM_KEYDOWN的响应函数OnKeyDown。判断如果按的键为“Esc”键,则调用CMainFrame类的函数EndFullScreen,便可退出全屏显示状态。
 

  void CFullScreenView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  {
if(nChar==VK_ESCAPE) // 如果按的键为Esc键
   {// 获取主框架窗口的指针

   CMainFrame *pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
   // 调用主窗口类的自定义函数 EndFullScreen ,便可退出全屏显示状态
  pFrame->EndFullScreen();

}
  CView::OnKeyDown(nChar, nRepCnt, nFlags);

}
 

  更改窗口图标并将其显示在任务栏

  以下两个函数可以为应用程序中的各子窗口显示一个任务条到任务栏并更改它们的图标。对那些象QQ一样隐藏主窗口的应用程序特别有用。

//函数用途:更改一个窗口的图标并将其显示在任务栏、任务切换条、任务管理器里
//参数说明:
//hWnd 要改变图标的窗口句柄
//hLargeIcon 显示到任务切换条上的图标 32*32
//hSmallIcon 显示到除任务切换条之外的图标 16*16
//hIcon 显示的图标,32*32,在显示到任务切换条之外的其余地方时会被自动压缩成16*16的。
//注释:
//此函数对于模式对话框无能为力。
//如果HICON 为NULL,函数不改变窗口图标,但是将原有图标显示到任务栏、
// 任务切换条、任务管理器里。
//此函数是通过将窗口的父窗口指针置空来实现将图标显示到任务栏、任务切换条、
// 任务管理器里的,所以调用完成后,其父窗口指针不再可用。
BOOL SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon);
BOOL SendWndIconToTaskbar(HWND hWnd,HICON hIcon);
BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon)
{
 BOOL ret = TRUE;
 ASSERT(hWnd);
 if(!::IsWindow(hWnd))
  return FALSE;
 //获取窗口指针
 CWnd* pWnd;
 pWnd = pWnd->FromHandle(hWnd);
 ASSERT(pWnd);
 if(!pWnd)
  return FALSE;
 //将父窗口设为NULL
 if(pWnd->GetParent())
  if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)
   return FALSE;

  if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))
   ret = FALSE;
  //设置窗口图标
  if(hLargeIcon && hSmallIcon)
  {
   pWnd->SetIcon(hSmallIcon,FALSE);
   pWnd->SetIcon(hLargeIcon,TRUE);
  }

  return ret;
 }

BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hIcon)
{
 BOOL ret = TRUE;
 ASSERT(hWnd);
 if(!::IsWindow(hWnd))
  return FALSE;
  //获取窗口指针
 CWnd* pWnd;
 pWnd = pWnd->FromHandle(hWnd);
 ASSERT(pWnd);
 if(!pWnd)
  return FALSE;
 //将父窗口设为NULL
 if(pWnd->GetParent())
  if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)
   return FALSE;

 if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))
  ret = FALSE;
 //设置窗口图标
 pWnd->SetIcon(hIcon,TRUE);
 pWnd->SetIcon(hIcon,FALSE);

 return ret;
}

 
 

  如何隐藏应用程序在任务栏上的显示

  对于CFrameWnd可以在PreCreateWindow()函数中修改窗口的风格。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |=WS_POPUP;//使主窗口不可见
cs.dwExStyle |=WS_EX_TOOLWINDOW;//不显示任务按钮
return CFrameWnd::PreCreateWindow(cs);
}

  对于其他窗口,可以在窗口被Create出来之后ShowWindow之前使用ModifyStyle()和ModifyStyleEx()来修改它的风格。

  如何控制窗口框架的最大最小尺寸?

  要控制一个框架的的最大最小尺寸,你需要做两件事情。

  第一步:在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,滚动条等等的大小。

// 最大最小尺寸的象素点 – 示例
#define MINX 200
#define MINY 300
#define MAXX 300
#define MAXY 400
void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
 CRect rectWindow;
 GetWindowRect(&rectWindow);

 CRect rectClient;
 GetClientRect(&rectClient);

 // get offset of toolbars, scrollbars, etc.
 int nWidthOffset = rectWindow.Width() – rectClient.Width();
 int nHeightOffset = rectWindow.Height() – rectClient.Height();

 lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;
 lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;
 lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;
 lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset;
}
 
 

  第二步:在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX消息,否则在最大化时你将得不到预料的结果.

BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
 cs.style &= ~WS_MAXIMIZEBOX;
 return CFrameWnd::PreCreateWindow(cs);
}
 

 
 

  如何修改frame窗口的背景颜色?

  MDI窗口的客户区是由frame窗口拥有的另一个窗口覆盖的。为了改变frame窗口背景的颜色,只需要这个客户区的背景颜色就可以了。你必须自己处理WM_ERASEBKND消息。下面是工作步骤:

  创建一个从CWnd类继承的类,就叫它CMDIClient吧;

  在CMDIFrameWnd中加入CMDIClient变量;(具体情况看下面的代码)
 

#include "MDIClient.h"
class CMainFrame : public CMDIFrameWnd
{

protected:
CMDIClient m_wndMDIClient;
}

  重载CMDIFrameWnd::OnCreateClient,下面是这段代码,请注意其中的SubclassWindow();
 

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )
{
m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
else
return FALSE;
}

  最后要在CMDIClient中加入处理WM_ERASEBKGND的函数。

  如何改变view的背景颜色?

  若要改变CView,CFrameWnd或CWnd对象的背景颜色需要处理WM_ERASEBKGND消息,下面就是一个范例代码:

BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
//设置brush为希望的背景颜色
CBrush backBrush(RGB(255, 128, 128));

//保存旧的brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect);

//画需要的区域
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);

return TRUE;

}
 

  若要改变CFromView继承类的背景颜色,下面是一个范例代码:

HBRUSH CMyFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
 switch (nCtlColor)
 {

  case CTLCOLOR_BTN:
  case CTLCOLOR_STATIC:
  {

   pDC->SetBkMode(TRANSPARENT);
   //不加任何处理或设置背景为透明

  }
  case CTLCOLOR_DLG:
  {

   CBrush* back_brush;
   COLORREF color;
   color = (COLORREF) GetSysColor(COLOR_BTNFACE);
   back_brush = new CBrush(color);
   return (HBRUSH) (back_brush->m_hObject);

  }

 }

 return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));

}
 

在任务栏状态区如何显示应用程序图标

  有关的数据由NOTIFYICONDATA结构描述:

 

typedef struct _NOTIFYICONDATA
{
DWORD cbSize; //结构的大小,必须设置
HWND hWnd; //接受回调消息的窗口的句柄
UINT uID; //应用程序定义的图标标志
UINT uFlags; //标志,可以是NIF_ICON、NIF_MESSAGE、NIF_TIP或其组合
UINT uCallbackMessage;//应用程序定义的回调消息标志
HICON hIcon; //图标句柄
char szTip[64]; //提示字串
} NOTIFYICONDATA, *PNOTIFYICONDATA;

  函数说明

  由Shell_NotifyIcon()函数向系统发送添加、删除、更改图标的消息。

WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(DWORD dwMessage,PNOTIFYICONDATA pnid);

  DwMessage为所发送消息的标志:

   NIM_ADD 添加图标到任务栏通知区;

   NIM_DELETE 删除任务栏通知区的图标;

   NIM_MODIFY 更改任务栏通知区的图标、回调消息标志、回调窗口句柄或提示字串;

   pnid为NOTIFYICONDATA结构的指针。

  回调信息的获得及处理

  如果一个任务栏图标有应用程序定义的回调消息,那么当这个图标有鼠标操作时,系统将给hWnd所标志的窗口发送下列的消息:
 

messageID = uCallbackMessage
wParam = uID
lParam = mouse event(例如WM_LBUTTONDOWN)

  通过这种方式,系统通知应用程序用户对图标的操作。如果一个应用程序生成了两个以上的图标,那么你可以根据wParam来判断是哪个图标返回的鼠标操作。通常,标准的Win95任务栏图标有以下鼠标操作响应:

  当鼠标停留在图标上时,系统应显示提示信息tooltip;

  当使用鼠标右键单击图标时,应用程序应显示快捷菜单;

  当使用鼠标左键双击图标时,应用程序应执行快捷菜单的缺省菜单项。

  在Microsoft Windows环境中,0×8000到0xBFFF的消息是保留的,应用程序可以定义自定义消息。

  关于消息处理的详细内容,请参考下一部分。

  源码及实现

  在本文中关于任务栏图标的类叫做CTrayIcon,这个类由CCmdTarget(或CObject)类派生,它有如下的成员变量和成员函数:

// TrayIcon.h
// CTrayIcon command target
class CTrayIcon : public CCmdTarget
{
public:
NOTIFYICONDATA m_nid;//NOTIFYICONDATA结构,你的图标要用的啊
BOOL m_IconExist;//标志,看看图标是不是已经存在了
CWnd* m_NotificationWnd;//接受回调消息的窗口,有它就不必经常AfxGetMainWnd了
public:
CWnd* GetNotificationWnd() const;//得到m_NotificationWnd
BOOL SetNotificationWnd(CWnd* pNotifyWnd);//设置(更改)m_NotificationWnd
CTrayIcon();//构造函数
virtual ~CTrayIcon();//析构函数
BOOL CreateIcon(CWnd* pNotifyWnd, UINT uID, HICON hIcon,
LPSTR lpszTip, UINT CallBackMessage);//在任务栏上生成图标
BOOL DeleteIcon();//删除任务栏上的图标
virtual LRESULT OnNotify(WPARAM WParam, LPARAM LParam);//消息响应函数
BOOL SetTipText(UINT nID);//设置(更改)提示字串
BOOL SetTipText(LPCTSTR lpszTip);//设置(更改)提示字串
BOOL ChangeIcon(HICON hIcon);//更改图标
BOOL ChangeIcon(UINT nID);//更改图标
BOOL ChangeIcon(LPCTSTR lpszIconName);//更改图标
BOOL ChangeStandardIcon(LPCTSTR lpszIconName);//更改为标准图标
……
};
 

  下面是成员函数的定义:

// TrayIcon.cpp
// CTrayIcon
CTrayIcon::CTrayIcon()
{//初始化参数
m_IconExist = FALSE;
m_NotificationWnd = NULL;
memset(&m_nid, 0, sizeof(m_nid));
m_nid.cbSize = sizeof(m_nid);//这个参数不会改变
}

CTrayIcon::~CTrayIcon()
{
if (m_IconExist)
DeleteIcon();//删除图标
}

BOOL CTrayIcon::CreateIcon(CWnd* pNotifyWnd, UINT uID, HICON hIcon,
LPSTR lpszTip, UINT CallBackMessage)
{
//确定接受回调消息的窗口是有效的
ASSERT(pNotifyWnd && ::IsWindow(pNotifyWnd->GetSafeHwnd()));

ASSERT(CallBackMessage >= WM_USER);//确定回调消息不发生冲突

ASSERT(_tcslen(lpszTip) <= 64);//提示字串不能超过64个字符

m_NotificationWnd = pNotifyWnd;//获得m_NotificationWnd

//设置NOTIFYICONDATA结构
m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
m_nid.uID = uID;
m_nid.hIcon = hIcon;
m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_nid.uCallbackMessage = CallBackMessage;

//设置NOTIFYICONDATA结构的提示字串
if (lpszTip)
lstrcpyn(m_nid.szTip, lpszTip, sizeof(m_nid.szTip));
else
m_nid.szTip[0] = ’’;

//显示图标
m_IconExist = Shell_NotifyIcon(NIM_ADD, &m_nid);
return m_IconExist;
}

BOOL CTrayIcon::DeleteIcon()
{//删除图标
if (!m_IconExist)
return FALSE;
m_IconExist = FALSE;
return Shell_NotifyIcon(NIM_DELETE, &m_nid);
}

LRESULT CTrayIcon::OnNotify(WPARAM WParam, LPARAM LParam)
{//处理图标返回的消息
if (WParam != m_nid.uID)//如果不是该图标的消息则迅速返回
return 0L;

//准备快捷菜单
CMenu menu;
if (!menu.LoadMenu(IDR_POPUP))//你必须确定资源中有ID为IDR_POPUP的菜单
return 0;
CMenu* pSubMenu = menu.GetSubMenu(0);//获得IDR_POPUP的子菜单
if (!pSubMenu)
return 0;

if (LParam == WM_RBUTTONUP)
{//右键单击弹出快捷菜单

//设置第一个菜单项为缺省
::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
CPoint pos;
GetCursorPos(&pos);

//显示并跟踪菜单
m_NotificationWnd->SetForegroundWindow();
pSubMenu->TrackPopupMenu(TPM_RIGHTALIGN|TPM_LEFTBUTTON
|TPM_RIGHTBUTTON, pos.x, pos.y, m_NotificationWnd, NULL);
}
else if (LParam == WM_LBUTTONDOWN)
{//左键单击恢复窗口
m_NotificationWnd->ShowWindow(SW_SHOW);//恢复窗口
m_NotificationWnd->SetForegroundWindow();//放置在前面
}
else if (LParam == WM_LBUTTONDBLCLK)
{//左键双击执行缺省菜单项
m_NotificationWnd->SendMessage(WM_COMMAND,
pSubMenu->GetMenuItemID(0), 0);
}
return 1L;
}

BOOL CTrayIcon::SetTipText(LPCTSTR lpszTip)
{//设置提示文字
if (!m_IconExist)
return FALSE;

_tcscpy(m_nid.szTip, lpszTip);
m_nid.uFlags |= NIF_TIP;

return Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}

BOOL CTrayIcon::SetTipText(UINT nID)
{//设置提示文字
 CString szTip;
 VERIFY(szTip.LoadString(nID));

 return SetTipText(szTip);
}
BOOL CTrayIcon::ChangeIcon(HICON hIcon)
{//更改图标
if (!m_IconExist)
return FALSE;

m_nid.hIcon = hIcon;
m_nid.uFlags |= NIF_ICON;

return Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}

BOOL CTrayIcon::ChangeIcon(UINT nID)
{//更改图标
 HICON hIcon = AfxGetApp()->LoadIcon(nID);
 return ChangeIcon(hIcon);
}

BOOL CTrayIcon::ChangeIcon(LPCTSTR lpszIconName)
{//更改图标
 HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName);
 return ChangeIcon(hIcon);
}

BOOL CTrayIcon::ChangeStandardIcon(LPCTSTR lpszIconName)
{//更改为标准图标
 HICON hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName);
 return ChangeIcon(hIcon);
}

BOOL CTrayIcon::SetNotificationWnd(CWnd * pNotifyWnd)
{//设置接受回调消息的窗口
 if (!m_IconExist)
  return FALSE;

 //确定窗口是有效的
 ASSERT(pNotifyWnd && ::IsWindow(pNotifyWnd->GetSafeHwnd()));

 m_NotificationWnd = pNotifyWnd;
 m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
 m_nid.uFlags |= NIF_MESSAGE;

 return Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}

CWnd* CTrayIcon::GetNotificationWnd() const
{//返回接受回调消息的窗口
 return m_NotificationWnd;
}
 

  三点补充:

  关于使用回调消息的补充说明:
 

  首先,在MainFrm.cpp中加入自己的消息代码;
 

// MainFrm.cpp : implementation of the CMainFrame class
//
#define MYWM_ICONNOTIFY WM_USER + 10//定义自己的消息代码

  第二步增加消息映射和函数声明,对于自定义消息不能由ClassWizard添加消息映射,只能手工添加。
 

// MainFrm.cpp : implementation of the CMainFrame class
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
//其他的消息映射
……
//}}AFX_MSG_MAP
ON_MESSAGE(WM_ICONNOTIFY,OnNotify)
END_MESSAGE_MAP()
并且在头文件中添加函数声明
// MainFrm.h
afx_msg LRESULT OnNotify(WPARAM WParam, LPARAM LParam);

  第三步增加消息处理函数定义
 

LRESULT CMainFrame::OnNotify(WPARAM WParam, LPARAM LParam)
{
return trayicon.OnNotify(WParam, LParam);//调用CTrayIcon类的处理函数
}

  如何隐藏任务栏上的按钮

  可以使用下列两种方法:

  1.在CreateWindowEx函数中使用WS_EX_TOOLWINDOW窗口式样(相反的如果要确保应用程序在任务栏上生成按钮,可以使用WS_EX_APPWINDOW窗口式样)。 The problem with this is that the window decorations are as for a small floating toolbar, which isn’t normally what’s wanted.

  2.生成一个空的隐藏的top-level窗口,并使其作为可视窗口的父窗口。

  3.在应用程序的InitInstance()函数中使用SW_HIDE式样调用ShowWindow()函数。
 

//pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->ShowWindow(SW_HIDE);
pMainFrame->UpdateWindow();

  如何动画任务栏上的图标
 

  在TrayIcon类中加入下列两个函数:

BOOL CTrayIcon::SetAnimateIcons(HICON* hIcon, UINT Number)
{//设置动画图标
 ASSERT(Number >= 2);//图标必须为两个以上
 ASSERT(hIcon);//图标必须不为空
 m_AnimateIcons = new HICON[Number];
 CopyMemory(m_AnimateIcons, hIcon, Number * sizeof(HICON));
 m_AnimateIconsNumber = Number;
 return TRUE;
}

BOOL CTrayIcon::Animate(UINT Index)
{//动画TrayIcon
 UINT i = Index % m_AnimateIconsNumber;
 return ChangeIcon(m_AnimateIcons[i]);
}
 

  怎样在应用程序中添加相应的菜单和函数

void CMainFrame::OnMenuAnimate()
{//动画TrayIcon,设置图标及定时器
 SetTimer(1, 500, NULL);
 HICON hIcon[3];
 hIcon[0] = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 hIcon[1] = AfxGetApp()->LoadIcon(IDR_MYTURNTYPE);
 hIcon[2] = AfxGetApp()->LoadStandardIcon(IDI_HAND);
 trayicon.SetAnimateIcons(hIcon, 3);
}
void CMainFrame::OnTimer(UINT nIDEvent)
{//动画TrayIcon
 UINT static i;
 i += 1;
 trayicon.Animate(i);

 CMDIFrameWnd::OnTimer(nIDEvent);
}

2005年11月30日

易易购(http://www.yiyigou.com/)是一个比较购物,购物搜索网站,通过做这个网站使自己对电子商务有了更多的理解

中国思想图书网(http://www.book100.cn/)是一个B2C的网站,成立五个月PR值4,Aleax排名7万多。

20046 —— 20051       

     目: 短信平台(VC++SQL Server 

 责任描述: 负责短信平台的升级、维护工作,熟悉CMPPSGIP协议

20038 —— 20042    

     目: 即时消息软件(VC++SQL ServerXML 

 项目描述: 基于XML的即时消息软件, 实现了聊天工具的基本功能(参照Jabber协议)

 责任描述: 完成了即时消息软件服务器端、客户端、数据库的设计和大部分开发工作

 20027 —— 20037        

 20027 —— 20037        

 20027 —— 20037        

     目: 手机网站开发软件VC++ MSHTMLXML XSLT   

 项目描述: 手机网站的开发、模拟工具

 责任描述: 负责XML XSLT相关部分的开发,在工作中认真踏实,负责的部分最稳定,bug最少。对MFCXML、设计模式进行了系统的学习。

 20013 —— 200110     

     目:HUATECH-1000VC++ Altigen板卡、SQL Server   

 项目描述:实现电话、web查询电话费用,自动语音服务,自动催缴,业务受理

 责任描述:负责IVR部分的概要设计、详细设计、开发

 

20006 —— 20013     

 

     目:UMS电话网关(VC++ Dialogic板卡、OracleSQL Server

           网上语音聊天软件(VC++  

 责任描述:负责多个程序、模块的设计、开发

 

19997 —— 20006          

 

CAD的二次开发立卧三面组合钻床三维模型的设计三维标准件库的开发

开发工具:VBVCAutoCADSolidWorks

IT技能
1.  精通C/C++、VC++
2.  精通ASP、XML、 XSLT、HTML
3.  精通 .Net框架、C#、UML
4.  精通SQL Server数据库系统
5.  熟悉Java、J2EE