传智播客旗下品牌:  黑马程序员  |  博学谷  |  传智专修学院

改变中国IT教育,我们正在行动     全国咨询热线:400-618-4000

C++培训之MFC-修改窗口的光标 图标 背景

更新时间:2015年12月28日16时32分 来源:传智播客C/C++学科

首先,创建一个单文档的应用程序。

在窗口创建之前修改

方式1

在我们创建的CMainFrame类的PreCreateWindow函数中写一个自己的窗口类并注册
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
       return FALSE;
    // TODO:  在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式
    WNDCLASS wc;
   wc.cbClsExtra = 0;
   wc.cbWndExtra = 0;
   wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
   wc.hCursor = LoadCursor(NULL, IDC_HELP);
   wc.hIcon = LoadIcon(NULL, IDI_ERROR);
   wc.hInstance = AfxGetInstanceHandle();
   wc.lpfnWndProc = ::DefWindowProc;
   wc.lpszClassName = _T("传智播客");
   wc.lpszMenuName = NULL;
   wc.style = CS_HREDRAW | CS_VREDRAW;
//注册窗口类
   RegisterClass(&wc);
   //类名称设置为我们设计的窗口类的名字
   cs.lpszClass = _T("传智播客");
    return TRUE;
}
上边的代码把我们的应用程序改成了黑色背景,帮助光标,错误图标。使用默认窗口过程函数。
关于为什么菜单被创建
运行程序发现只有图标改变了,背景和光标并没有改变,菜单项也没有消失,为什么呢?
在利用MFC向导生成SDI应用程序时,在应用程序类的InitInstance函数中有如下代码:
    // 注册应用程序的文档模板。  文档模板
    // 将用作文档、框架窗口和视图之间的连接
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
       IDR_MAINFRAME,
       RUNTIME_CLASS(CMenuDoc),
       RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口
       RUNTIME_CLASS(CMenuView));
    if (!pDocTemplate)
       return FALSE;
    AddDocTemplate(pDocTemplate);
也就是说在创建文档模板时,将菜单资源标识(IDR_MAINFRAME)作为其中的一个参数传入,当MFC底层代码在创建框架窗口时,就会将此标识转换为相应菜单句柄,然后去创建菜单和框架窗口。因此在这里将菜单设置为NULL,并不会影响菜单的创建。
关于为什么窗口背景和光标没有改变
应用程序包含连个窗口:
l  应用程序框架窗口
l  视类窗口
前者包含了后者,后者覆盖在前者上面。程序运行后我们看到的窗口实际上是视类窗口,而我们代码中实际上修改的是框架窗口的背景和光标。应用程序的图标属于框架窗口,所以程序运行后看到图标改变了。
改变背景和光标的操作我们应该放在视类中实现,我们应该在视类窗口创建之前,即在PreCreateWindow函数中将窗口类设置为先前自定义的那个类,因为这是那个窗口类已经注册了,所以可以直接使用那么窗口类的名字:
BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs)
{
       // TODO:  在此处通过修改
       //  CREATESTRUCT cs 来修改窗口类或样式
       cs.lpszClass = _T("传智播客");
       return CView::PreCreateWindow(cs);
}
在MFC中如果想修改应用程序的窗口的图标,应该在框架类中进行,因为框架窗口中才有标题栏,所以才能修改位于标题栏上的图标。如果想修改应用程序窗口的背景和光标,就应该在视类中进行。

方式2

通过上边的例子我们可以知道,在框架类中只能修改窗口的图标,而为了实现这一功能,我们需要重写整个窗口类。显然,这是一件很麻烦的事情,MFC给我们提供了一个全局函数: AfxRegisterWndClass,用来设定窗口的类型、光标、图标、背景。其函数原型定义如下:
        LPCTSTR AFXAPI AfxRegisterWndClass(
             UINT nClassStyle,
             HCURSOR hCursor = 0,
             HBRUSH hbrBackground = 0,
             HICON hIcon = 0
);
设置图标:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
       if( !CFrameWnd::PreCreateWindow(cs) )
           return FALSE;
       // TODO:  在此处通过修改
       //  CREATESTRUCT cs 来修改窗口类或样式
       cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 0, 0,
         LoadIcon(NULL, IDI_ERROR));
       return TRUE;
}
设置光标和背景色:
BOOL CMenuView::PreCreateWindow(CREATESTRUCT& cs)
{
       // TODO:  在此处通过修改
       //  CREATESTRUCT cs 来修改窗口类或样式
       cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
LoadCursor(NULL, IDC_HELP),
(HBRUSH)GetStockObject(BLACK_BRUSH), NULL);
       return CView::PreCreateWindow(cs);
}

在窗口创建之后修改

使用Windows API函数 SetClassLong
函数原型如下:
DWORD SetClassLong(HWND hWnd,int nlndex,LONG dwNewLong)
参数:
l  hWnd:窗口句柄及间接给出的窗口所属的类。
l  nIndex: 指定要设置的索引
n  GCL_HBRBACKGROUND 设置新的背景画刷
n  GCL_HCURSOR 设置新的光标
n  GCL_HICON 设置新的图标
n  GCL_STYLE 设置新的窗口样式

设置图标:

在CMainFram类的OnCreate函数最后,return语句之前添加如下代码:
    SetClassLong(m_hWnd, GCL_HICON, (LONG)LoadIcon(NULL, IDI_ERROR));

设置光标和背景

在莹莹程序生成的视类的OnCreate函数最后,return语句之前添加如下代码:
    //背景色
SetClassLong(m_hWnd, GCL_HBRBACKGROUND,
 (LONG)(HBRUSH)GetStockObject(BLACK_BRUSH));
    //光标
    SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_HELP));

本文版权归传智播客C++培训学院所有,欢迎转载,转载请注明作者出处。谢谢!
作者:传智播客C/C++培训学院
首发:http://www.itcast.cn/c/